MyBatis快速入门第二讲——MyBatis的快速入门

MyBatis介绍

MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。MyBatis是一个优秀的持久层框架,它对JDBC的操作数据库的过程进行了封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建Connection、创建Statement、手动设置参数、结果集检索等JDBC繁杂的过程代码了。
MyBatis通过xml或注解的方式将要执行的各种Statement(Statement、PreparedStatemnt、CallableStatement)配置起来,并通过Java对象和Statement中的SQL进行映射生成最终执行的SQL语句,最后由MyBatis框架执行SQL语句并将结果映射成Java对象并返回。

MyBatis框架的架构

知道了MyBatis框架是个什么东东之后,我们还需要从全局或者整体上对MyBatis框架有一个比较清晰的认识,MyBatis框架的架构如下图所示。
这里写图片描述
对于以上架构图,我们该怎样去理解呢?可以从以下几点去理解。

  1. SqlMapConfig.xml,此文件作为MyBatis的全局配置文件,配置了MyBatis的运行环境等信息。mapper.xml文件即SQL映射文件,文件中配置了操作数据库的SQL语句,此文件需要在SqlMapConfig.xml文件中进行加载;
  2. 通过MyBatis环境等配置信息构造SqlSessionFactory(即会话工厂);
  3. 由会话工厂创建SqlSession(即会话),操作数据库需要通过SqlSession;
  4. MyBatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器;
  5. MappedStatement也是MyBatis一个底层封装对象,它包装了MyBatis配置信息以及SQL映射信息等。mapper.xml文件中一个SQL对应一个MappedStatement对象,SQL的id即是MappedStatement对象的id
  6. MappedStatement对象对SQL执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过该对象在执行SQL前将输入的Java对象映射至该SQL中,输入参数映射就是JDBC编程中对PreparedStatement对象设置参数;
  7. MappedStatement对象对SQL执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过该对象在执行SQL后将输出结果映射至Java对象中,输出结果映射过程相当于JDBC编程中对结果集的解析处理过程。

MyBatis入门

MyBatis下载

MyBatis框架的代码现在是由Github来管理的,地址是https://github.com/mybatis/mybatis-3/releases。大家可从该地址下载最新版本的MyBatis框架。温馨提示:本系列教程使用的是mybatis-3.2.7这个版本的MyBatis框架,该版本的MyBatis框架的目录结构如下图所示。
这里写图片描述

开发需求

首先,我们肯定是要明确开发需求的,即使用MyBatis框架能干啥?我们可以使用MyBatis框架来实现以下功能:

  1. 根据用户id查询用户信息;
  2. 根据用户名称模糊查询用户信息列表;
  3. 添加用户;
  4. 更新用户;
  5. 删除用户。

环境搭建

开发需求明确之后,我们就要搭建开发环境了。开发环境搭建的详细步骤如下:

  • 【第一步】,使用Eclipse创建一个普通的Java工程,例如01-mybatis;
  • 【第二步】,加入jar包。工程所需加入的jar包有MyBatis核心包、依赖包以及MySQL数据驱动包。
    在这里插入图片描述
  • 【第三步】,在classpath下创建一个日志记录文件(命名为log4j.properties就好)。我们可在01-mybatis工程下新建一个config源码包,并在该源码包下创建一个日志记录文件,即log4j.properties。
    在这里插入图片描述
    该日志记录文件的内容如下:
    # Global logging configuration
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    
    在这里,我们必须明确一点的就是,MyBatis框架默认使用log4j来输出日志信息。
  • 【第四步】,在classpath下创建SqlMapConfig.xml文件。我们同样可以在config源码包下创建该文件。
    在这里插入图片描述
    一开始,我们不妨将该文件中的内容写成下面这样:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<!-- 和spring整合后 environments配置将废除, default属性表示使用哪一个环境? -->
    	<environments default="development">
    		<environment id="development">
    			<!-- 使用jdbc事务管理 -->
    			<transactionManager type="JDBC" />
    			<!-- 数据库连接池 -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.jdbc.Driver" />
    				<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
    				<property name="username" value="root" />
    				<property name="password" value="liayun" />
    			</dataSource>
    		</environment>
    		<environment id="test">
    			<!-- 使用jdbc事务管理 -->
    			<transactionManager type="JDBC" />
    			<!-- 数据库连接池 -->
    			<dataSource type="POOLED">
    				<property name="driver" value="com.mysql.jdbc.Driver" />
    				<property name="url"
    					value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
    				<property name="username" value="root" />
    				<property name="password" value="liayun" />
    			</dataSource>
    		</environment>
    	</environments>
    </configuration>
    
    SqlMapConfig.xml是MyBatis框架的核心配置文件,以上文件的配置内容为数据源、事务管理。温馨提示:等后面MyBatis和Spring两个框架整合之后,environments的配置将被废除。
  • 【第五步】,创建一个po类,即User.java。我们可在src目录下新建一个名为com.meimeixia.mybatis.pojo的包,并在该包下创建一个po类(即User.java)。该po类将作为MyBatis进行SQL映射使用,po类通常与数据库表相对应。
    public class User {
    	private int id;
    	private String username;// 用户姓名
    	private String sex;// 性别
    	private Date birthday;// 生日
    	private String address;// 地址
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getSex() {
    		return sex;
    	}
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	public Date getBirthday() {
    		return birthday;
    	}
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    	public String getAddress() {
    		return address;
    	}
    	public void setAddress(String address) {
    		this.address = address;
    	}
    	@Override
    	public String toString() {
    		return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
    				+ address + "]";
    	}
    }
    
  • 【第六步】,在classpath下的config源码包中新建一个普通的目录,例如mybatis,并在该目录下创建一个SQL映射文件,例如user.xml。
    在这里插入图片描述
    一开始,我们将该文件中的内容写成下面这样:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="user">
    
    </mapper>
    
    namespace:即命名空间,它主要用于隔离SQL语句(即不同SQL映射文件中的两个相同id的SQL语句如何来区分),这只是当前的作用,后续会讲另一层非常重要的作用。
  • 【第七步】,加载以上SQL映射文件。MyBatis框架需要加载SQL映射文件,如何在SqlMapConfig.xml中加载user.xml文件呢?我们可以在SqlMapConfig.xml配置文件中添加如下配置信息:
    <!-- 加载映射文件 -->
    <mappers>
    	<!-- 第一种方式:resource属性表示基于classpath来查找咱们的映射文件 -->
    	<mapper resource="mybatis/user.xml" />
    </mappers>
    
    正如下图所示的那样:
    在这里插入图片描述

根据用户id查询用户信息

首先,在user.xml映射文件中添加如下配置:
在这里插入图片描述
针对以上<select>标签的配置,我觉得有必要说明如下几点:

  • id:表示SQL语句的id,即SQL语句的唯一标识;
  • parameterType:查询参数(入参)的数据类型,即定义输入到SQL语句中的映射类型;
  • resultType:查询结果的数据类型,若是pojo则应该给出全路径。

还有一点需要说明,SQL语句中的#{id2}表示使用PreparedStatement设置占位符号并将输入变量id2传到SQL语句中。说得直白点,#{}就是一个占位符,相当于JDBC中的?,如果入参为普通数据类型,例如Integer、String等,那么{}内部就可以随便写了!
然后,在src目录下新建一个名为com.meimeixia.mybatis.test的包,并在该包下创建一个名为MybatisTest的单元测试类,紧接着在该类中编写一个如下的单元测试方法。

package com.meimeixia.mybatis.test;

import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.meimeixia.mybatis.pojo.User;

public class MybatisTest {

	@Test
	public void testGetUserById() throws IOException {
		//创建SqlSessionFactoryBuilder对象
		SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
		//1. 加载核心配置文件(创建核心配置文件的输入流对象)
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		//2. 创建SqlSessionFactory对象(通过核心配置文件的输入流对象创建SqlSessionFactory对象)
		SqlSessionFactory sqlSessionFactory = ssfb.build(inputStream);
		//3. 创建SqlSession对象,调用其API,得到一个结果集
		//创建SqlSession对象
		SqlSession sqlSession = sqlSessionFactory.openSession();
		//执行查询,参数一:SQL语句的ID(规范一点的话,最好带上命名空间),参数二:入参
		User user = sqlSession.selectOne("user.getUserById", 1);
		//输出结果
		System.out.println(user);
		//释放资源
		sqlSession.close();
	}

}

以上完成的需求就是根据用户id来查询用户信息。运行以上单元测试方法,你可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
一般来讲,工厂对象一般在实际开发是单例的,并不需要频繁地创建,所以我们可以抽取出一个工具类,专门用于创建SqlSessionFactory对象。我们可以在src目录下新建一个名为com.meimeixia.mybatis.utils的包,并在该包下创建一个名为SqlSessionFactoryUtils的工具类。

package com.meimeixia.mybatis.utils;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * SqlSessionFactory工具类
 * @author liayun
 *
 */
public class SqlSessionFactoryUtils {
	
	private static SqlSessionFactory sqlSessionFactory;
	
	static {
		try {
			//创建SqlSessionFactoryBuilder对象
			SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();
			//创建核心配置文件的输入流
			InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
			//通过核心配置文件的输入流创建SqlSessionFactory对象
			sqlSessionFactory = ssfb.build(inputStream);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	/**
	 * 获取SqlSessionFactory对象
	 * @return
	 */
	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}
	
}

如此一来,MybatisTest单元测试类中的testGetUserById方法便可以写成下面这样了。

@Test
public void testGetUserById() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	//执行查询,参数一:SQL语句的ID(规范一点的话,最好带上命名空间),参数二:入参
	User user = sqlSession.selectOne("user.getUserById", 1);
	//输出结果
	System.out.println(user);
	//释放资源
	sqlSession.close();
}

根据用户名称模糊查询用户信息列表

现在我们就要来完成第二个需求,即根据用户名称模糊查询用户信息列表了。首先,在user.xml映射文件中添加如下配置。
在这里插入图片描述
这里需要说明的一点是,如果查询结果返回的是List集合,那么resultType属性的值只需要设置为List集合中的一个元素的数据类型即可。
然后,在MybatisTest单元测试类编写一个如下的单元测试方法。

@Test
public void testGetByUserName() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	List<User> list = sqlSession.selectList("user.getUserByUserName", "%张%");
	for (User user : list) {
		System.out.println(user);
	}
	//释放资源
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
在实际开发中建议使用#{}占位符这种方式,因为这样可以防止SQL注入。除了以上这种方式外,在此我还介绍第二种方式,即在user.xml映射文件中添加如下配置:
在这里插入图片描述
${value}表示使用参数将${value}替换,做字符串的拼接,${}为字符串拼接指令。温馨提示:如果是取简单数据类型的参数,括号中的值必须为value。
如此一来,MybatisTest单元测试类中的testGetByUserName方法就要修改成下面这个样子了。

@Test
public void testGetByUserName() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	List<User> list = sqlSession.selectList("user.getUserByUserName", "张");
	for (User user : list) {
		System.out.println(user);
	}
	//释放资源
	sqlSession.close();
}

此时,运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
很明显这种方式在实际开发中是不建议使用的,因为无法防止SQL注入。

小结

#{}和${}

#{}表示一个占位符号,可以很好地去避免SQL注入。其原理是将占位符位置的整个参数和SQL语句两部分提交给数据库,数据库去执行SQL语句,去表中匹配所有的记录是否和整个参数一致。
在这里插入图片描述
${}表示一个SQL拼接符号,其原理是在向数据库发出SQL语句之前去拼接好SQL语句再提交给数据库执行。
在这里插入图片描述
一般情况下建议使用#{},只有在特殊情况下才必须要用到${},比如:

  • 动态拼接SQL中动态组成排序字段,要通过${}将排序字段传入SQL中;
  • 动态拼接SQL中动态组成表名,要通过${}将表名传入SQL中。

parameterType和resultType

在这里插入图片描述

selectOne()和selectList()方法

  • 使用SqlSession对象中的selectOne方法可以查询一条记录,但如果使用selectOne方法查询多条记录则会抛出如下异常:
    这里写图片描述
  • 使用SqlSession对象中的selectList方法可以查询一条或多条记录。

添加用户

现在我们就要来完成第三个需求,即添加用户了。首先,在user.xml映射文件中添加如下配置。
在这里插入图片描述
如果输入参数是pojo,那么#{}中要写的东东就是pojo类中的属性了(用到了对象图导航的思想),此时就不能随便写了。
然后,试着在MybatisTest单元测试类中编写一个如下的单元测试方法。

@Test
public void testInsertUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setUsername("鲁达");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("广州黄埔刘村");

	sqlSession.insert("user.insertUser", user);
	//释放资源
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
虽然发出了SQL语句,但是事务并没将其提交,而是回滚了。所以,User对象是无法插入到数据库user表中的。此时,我们应该将testInsertUser单元测试方法修改成下面这个样子,才能真正将User对象插入到数据库user表中。

@Test
public void testInsertUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setUsername("鲁达");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("广州黄埔刘村");
	
	sqlSession.insert("user.insertUser", user);
	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

再次运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
事务已提交,可发现数据库user表中插入了一条记录。不知你有没有想过SqlSession对象的insert方法的返回值代表的是什么?想必不用我说,你就应该清楚insert方法返回的是数据库影响的行数。你可以尝试着将testInsertUser单元测试方法修改成下面这个样子。

@Test
public void testInsertUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setUsername("鲁达222");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("广州黄埔刘村");
	int insert = sqlSession.insert("user.insertUser", user);
	System.out.println(insert);//返回的是数据库影响的行数

	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

此时,运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
足以说明insert方法返回的是数据库影响的行数了。

MySQL自增主键返回

现在有这样一个需求:在成功向数据库user表中插入一条记录后,想要得到MySQL数据库给我们生成的主键id,即获取主键。如何实现这个需求呢?这里就要用到MySQL数据库中的一个内置函数(即LAST_INSERT_ID())了,它返回的是auto_increment自增列新记录ID值,即它能查询出最后一条记录插入的ID值。该函数是在当前事务下取到你最后插入到表中的那条记录的ID值,而我们应知道查询操作是不需要开启事务的,增删改操作是需要开启事务的。温馨提示:该函数的调用是和会话有关的,也就是说在每一个连接里面,如果有这个函数,那么这个函数便是线程安全的!
如此一来,我们就需要将user.xml映射文件中的<insert>标签的配置修改成下面这个样子(即添加selectKey实现将主键返回):
在这里插入图片描述
针对以上<selectKey>标签的配置,我觉得有必要说明如下几点:

  • keyProperty:返回的主键存储在pojo中的哪个属性(即其对应pojo的主键属性)上。获取主键,实际上是将主键取出来之后封装到了pojo的主键属性当中;
  • resultType:返回的主键是什么类型(即其对应pojo的主键的数据类型);
  • order:selectKey的执行顺序,是相对于insert语句来说的,由于MySQL的自增原理,执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为AFTER。

为了获取MySQL自增主键,我们还需要将testInsertUser单元测试方法修改成下面这个样子。

@Test
public void testInsertUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setUsername("鲁达333");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("广州黄埔刘村");
	
	sqlSession.insert("user.insertUser", user);
	System.out.println(user);
	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
其实,user.xml映射文件中的<insert>标签可以简写成下面这个样子,一样可以获取到MySQL自增主键。
在这里插入图片描述

返回UUID算法生成的主键

在这一小节中,为了方便演示,需要提前做两件事情,第一件事情是在数据库user表中加上一个uuid2字段。
在这里插入图片描述
第二件事情是在User类上加上相应属性,即uuid2属性。

package com.meimeixia.mybatis.pojo;

import java.util.Date;

public class User {

	private Integer id;
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址
	
	private String uuid2;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
	
	public String getUuid2() {
		return uuid2;
	}

	public void setUuid2(String uuid2) {
		this.uuid2 = uuid2;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
				+ address + ", uuid2=" + uuid2 + "]";
	}

}

在使用UUID算法生成主键时,需要增加通过SELECT UUID()语句得到一个UUID值作为主键。这时,我们可以在user.xml映射文件中添加如下配置。
在这里插入图片描述
因为是使用UUID算法生成主键,所以应该先生成主键然后再向数据库中插入数据,此时order属性的值应是BEFORE。
为了获取到UUID算法生成的主键,我们还需要在MybatisTest单元测试类中编写一个如下的单元测试方法。

@Test
public void testInsertUserUUID() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setUsername("武松");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("广州黄埔刘村");
	sqlSession.insert("user.insertUserUUID", user);
	System.out.println(user);
	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

试着运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
不知你有没有想过一个问题,如果要是将以上<insert>标签修改成下面这个样子,那么会出现什么现象呢?如果在MyBatis中配置了一个selectKey的话,那么<insert>标签上的useGeneratedKeys="true" keyProperty="id"配置默认就不生效了!!!
在这里插入图片描述

删除用户

现在我们就要来完成第四个需求,即删除用户了。首先,在user.xml映射文件中添加如下配置:
在这里插入图片描述
然后,在MybatisTest单元测试类编写一个如下的单元测试方法。

@Test
public void testDeleteUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	sqlSession.delete("user.deleteUser", 38);
	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述

更新用户

现在我们就要来完成第五个需求,即更新用户了。首先,在user.xml映射文件中添加如下配置:
在这里插入图片描述
然后,在MybatisTest单元测试类编写一个如下的单元测试方法。

@Test
public void testUpdateUser() {
	//获取SqlSessionFactory对象
	SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
	//创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	User user = new User();
	user.setId(39);
	user.setUsername("张无忌");
	sqlSession.update("user.updateUser", user);
	//手动提交事务(在Mybatis中,事务是默认不提交的)
	sqlSession.commit();
	//释放资源
	sqlSession.close();
}

运行以上单元测试方法,你便可以看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
其实,调用SqlSession对象的insert方法同样也可以达到更新用户的效果。
在这里插入图片描述
为什么不这样做呢?其实理论上是应该要调用update方法的,即使调用insert方法不影响最后的结果,但是我们要习惯性调用相应的方法,这样代码也会好看一点!

MyBatis解决了JDBC编程的问题

还记得《MyBatis快速入门第一讲——使用传统的JDBC编程所带来的问题》一文中使用JDBC编程所带来的问题吗?现在使用MyBatis这个框架就可以解决JDBC编程所带来的这些问题了。

  1. 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
    如何解决这个问题呢? 可以在SqlMapConfig.xml文件中配置数据库连接池,使用连接池管理数据库连接。
  2. SQL语句写在代码中造成代码不易维护,实际应用中SQL语句变化的可能较大,如果SQL语句一旦变动,那么就需要改变Java代码了。
    如何解决这个问题呢? 可以将SQL语句配置在映射文件中与Java代码分离。
  3. 向SQL语句传参数麻烦,因为SQL语句的where条件不一定,可能多也可能少,修改SQL语句还要修改Java代码,导致系统不易维护。
    如何解决这个问题呢? MyBatis可以自动将Java对象映射至SQL语句中,通过Statement中的parameterType定义输入参数的类型。
  4. 对结果集解析麻烦,SQL变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析则比较方便。
    如何解决这个问题呢? MyBatis可以自动将SQL语句的执行结果映射至Java对象,通过Statement中的resultType定义输出结果的类型。

MyBatis与Hibernate的不同之处

MyBatis和Hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写SQL语句,不过MyBatis可以通过XML或注解方式灵活配置要运行的SQL语句,并将Java对象和SQL语句映射生成最终执行的SQL,最后将SQL执行的结果再映射生成Java对象。
MyBatis学习门槛低,简单易学,程序员直接编写原生态SQL,可严格控制SQL执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是MyBatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套SQL映射文件,工作量大。
Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件),如果用Hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好的。
我个人总结的MyBatis与Hibernate这两个框架的不同之处:

  • MyBatis是不完全的ORM框架,它学习成本低,入门门槛也低。MyBatis需要程序员自己写SQL,对SQL修改和优化就比较灵活。适用场景:需求变化较快的项目开发,比如互联网项目、电商等;
  • Hibernate学习成本高,入门门槛高,Hibernate是ORM框架,不需要程序员编写SQL,自动根据对象映射生成SQL。适用场景:需求固定的中小型项目,如OA系统、ERP系统。

企业在技术选型上应考虑各个技术框架的特点去进行选型,企业要根据人力、物力等资源去衡量,以节省成本、利润最大化为目标进行选型。

相关推荐
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页