MyBatis-核心对象
基于前面的学习,我们对MyBatis有了初步认识。
下面正式介绍一下MyBatis的三个基本要素:
- 核心接口和类;
- MyBatis核心配置文件(mybatis-config.xml);
- SQL映射文件(mapper.xml)。
本篇主要介绍MyBatis的核心接口和类,如图所示:

(1)每个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心;
(2)首先以根据XML配置文件或Configuration类的实例构建该对象;
(3)然后获取SqlSessionFactory对象,该对象实例可以通过SqlSessionFactoryBuilder对象来获得。
(4)有了SqlSessionFactory对象之后,就可以进而获取SqlSession实例,SqlSession对象中完全包含以数据库为背景的所有执行SQL操作的方法。可以用该实例直接执行已映射的SQL语句。
一、SqlSessionFactoryBuilder
1. SqlSessionFactoryBuilder的作用
SqlSessionFactoryBuilder负责构建SqlSessionFactory,并且提供了多个build()方法的重载,如图所示:

通过源码分析,可以发现都是在调用同一签名方法:
build(InputStream inputStream, String environment, Properties properties)
由于方法参数environment和properties都可以为null,那么去除重复的,真正的重载方法其实只有如下三种:
build(Reader reader, String environment, Properties properties)
build(InputStream inputStream, String environment, Properties properties)
build(Configuration config)
通过上述分析,发现配置信息可以以三种形式提供给SqlSessionFactoryBuilder的build()方法,分别是InputStream(字节流)、Reader(字符流)、Configuration(类)。
由于字节流与字符流都属于读取配置文件的方式,所以从配置信息的来源就很容易想到构建一个SqlSessionFactory有两种方式:读取XML配置文件构造方式和编程构造方式。
在本篇中,我们采用读取XML配置文件的方式来构造SqlSessionFactory。
2. SqlSessionFactoryBuilder的生命周期和作用域
SqlSessionFactoryBuilder的最大特点是:用过即丢。
一旦创建了SqlSessionFactory对象之后,这个类就不再需要存在了。
因此SqlSessionFactoryBuilder的最佳范围就是存在于方法体内,也就是局部变量而已。
二、SqlSessionFactory
1. SqlSessionFactory的作用
SqlSessionFactory简单的理解就是创建SqlSession实例的工厂。
所有的MyBatis应用都是以SqlSessionFactory实例为中心。
SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder对象来获得。
有了它之后,顾名思义,就可以通过SqlSessionFactory提供的openSession()方法来获取SqlSession实例。
如图所示:

【注意】
openSession()方法的参数为boolean值时,若传入true表示关闭事务控制,自动提交;false表示开启事务控制。若不传入参数,默认为true。
openSession(boolean autoCommit)
openSession() // 若不传入参数,默认为true,自动提交
2. SqlSessionFactory的声明周期和作用域
SqlSessionFactory对象一旦创建,就会在整个应用运行过程中始终存在。
没有理由去销毁或再创建它,并且在应用运行中也不建议多次创建SqlSessionFactory。
因此,SqlSessionFactory的最佳作用域时Application,即随着应用的生命周期一同存在。
那么这种“存在于整个应用运行期间,并且同时只存在一个对象实例”的模式就是所谓的单例模式(指在应用运行期间有且仅有一个实例)。
下面就需要把获取SqlSessionFactory的代码进行优化,最简单的实现方式就是放在静态代码块下,以保证SqlSessionFactory对象只被创建一次。
实现步骤如下。
(1)创建工具类MyBatisUtil.java,在静态代码块中创建SqlSessionFactory对象。
package com.smbms.util;
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;
public class MyBatisUtil {
private static SqlSessionFactory factory;
static{
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
}
(2)创建SqlSession对象和关闭SqlSession。
public static SqlSession createSqlSession(){
return factory.openSession(false); // true为自动提交事务
}
public static void closeSqlSession(SqlSession sqlSession){
if(null != sqlSession)
sqlSession.close();
}
通过以上静态类的方式来保证SqlSessionFactory实例只被创建一次。
当然,最佳的解决方案是使用依赖注入容器 – Spring框架来管理SqlSessionFactory的单例声明周期。
关于和Spring的集成,我们会在以后的学习中进行讲解。
完整的com.smbms.util.MyBatisUtil.java代码如下:
package com.smbms.util;
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;
/**
* @文件描述 MyBatis工具类
* @创建用户 lkw
* @创建时间 2017年5月19日 上午2:08:11
*/
public class MyBatisUtil {
// SqlSession工厂
private static SqlSessionFactory factory;
// 初始化SqlSessionFactory
static{
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建SqlSession实例
*/
public static SqlSession createSqlSession(){
return factory.openSession(false); // true为自动提交事务
}
/**
* 关闭SqlSession实例
*/
public static void closeSqlSession(SqlSession sqlSession){
if(null != sqlSession)
sqlSession.close();
}
}
// 示例:MyBatisDemo02
【注意】
设计模式中的单例模式,我们会在后续的SpringMVC学习中具体展开讲解,此处先稍作了解即可。
三、SqlSession
1. SqlSession的作用
SqlSession是用于执行持久化操作的对象,类似于JDBC中的Connection。
它提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句。
如图所示:

2. SqlSession的生命周期和作用域
正如其名,SqlSession对应着一次数据库会话。
由于数据库会话不是永久的,因此SqlSession的生命周期也不应该是永久的。
相反,在每次访问数据库时都需要创建它。
(注意,并不是说在SqlSession里只能执行一次SQL,是完全可以执行多次的,但是如果关闭了SqlSession,那么就需要重新创建它)
需要注意的是,每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。
因此最佳的作用域范围是request作用域或者方法体作用域内。
关闭SqlSession是非常重要的,必须要确保SqlSession在finally语句块中正常关闭。
可以使用下面的标准方式来关闭:
SqlSession session = sqlSessionFactory.openSessopn();
try {
// do work
} finally {
session.close();
}
3. SqlSession的两种使用方式
(1)方法一
通过SqlSession实例来直接执行已映射的SQL语句。
例如,通过调用selectList()方法执行用户表的查询操作,步骤如下:
添加User实体类(com.smbms.pojo.User.java):
package com.smbms.pojo;
import java.util.Date;
/**
* @文件描述 实体类,用户信息
* @创建用户 lkw
* @创建时间 2017年5月19日 上午2:15:01
*/
public class User {
// 字段
private Integer id; //id
private String userCode; //用户编码
private String userName; //用户名称
private String userPassword; //用户密码
private Integer gender; //性别
private Date birthday; //出生日期
private String phone; //电话
private String address; //地址
private Integer userRole; //用户角色
private Integer createdBy; //创建者
private Date creationDate; //创建时间
private Integer modifyBy; //更新者
private Date modifyDate; //更新时间
// 省略 getters & setters
}
新增User的SQL映射文件(com/smbms/dao/user/UserMapper.xml),并增加查询用户列表的select节点:
<?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="com.smbms.dao.user.UserMapper">
<!-- 查询用户表记录数 -->
<select id="count" resultType="int">
select count(1) as count from smbms_user
</select>
<!-- 查询用户列表 -->
<select id="getUserList" resultType="com.smbms.pojo.User">
select * from smbms_user
</select>
</mapper>
在mybatis-config.xml的mappers中添加UserMapper.xml的映射:
<!-- 将mapper文件加入到配置文件中 -->
<mappers>
<mapper resource="com/smbms/dao/user/UserMapper.xml"/>
</mappers>
在test下新建测试类com.smbms.dao.user.UserMapperTest.java,调用selectList()方法执行查询操作:
package com.smbms.dao.user;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import com.smbms.pojo.User;
import com.smbms.util.MyBatisUtil;
/**
* @文件描述 测试类,用户信息
* @创建用户 lkw
* @创建时间 2017年5月19日 上午2:19:07
*/
public class UserMapperTest {
// LOG4J
private Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void testGetUserList(){
SqlSession sqlSession = null;
List<User> userList = new ArrayList<User>();
try {
sqlSession = MyBatisUtil.createSqlSession();
//第一种方式:调用selectList方法执行查询操作
userList = sqlSession.selectList("com.smbms.dao.user.UserMapper.getUserList");
} catch (Exception e) {
e.printStackTrace();
}finally{
MyBatisUtil.closeSqlSession(sqlSession);
}
for(User user: userList){
logger.debug("UserCode: " + user.getUserCode() + ", UserName: " + user.getUserName());
}
}
}
// 示例:MyBatisDemo03
(2)方法2
创建绑定映射语句的接口UserMapper.java,并提供接口方法getUserList(),该接口成为映射器。
注意,接口的方法必须与SQL映射文件中SQL语句的ID一一对应:
package com.smbms.dao.user;
import java.util.List;
import com.smbms.pojo.User;
public interface UserMapper {
/**
* 查询用户表记录数
* @return
*/
public int count();
/**
* 查询用户列表
* @return
*/
public List<User> getUserList();
}
修改测试类UserMapperTest.java,调用getMapper(Mapper.class)执行Mapper接口方法来实现对数据的查询操作:
package com.smbms.dao.user;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import com.smbms.pojo.User;
import com.smbms.util.MyBatisUtil;
/**
* @文件描述 测试类,用户信息
* @创建用户 lkw
* @创建时间 2017年5月19日 上午2:19:07
*/
public class UserMapperTest {
// LOG4J
private Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void testGetUserList(){
SqlSession sqlSession = null;
List<User> userList = new ArrayList<User>();
try {
sqlSession = MyBatisUtil.createSqlSession();
//第一种方式:调用selectList方法执行查询操作
//userList = sqlSession.selectList("com.smbms.dao.user.UserMapper.getUserList");
//第二种方式:调用getMapper(Mapper.class)执行dao接口方法来实现对数据库的查询操作
userList = sqlSession.getMapper(UserMapper.class).getUserList();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
MyBatisUtil.closeSqlSession(sqlSession);
}
for(User user: userList){
logger.debug("UserCode: " + user.getUserCode() + ", UserName: " + user.getUserName());
}
}
}
// 示例:MyBatisDemo03
【注意】
第一种方式是旧版本的MyBatis提供的操作方式,虽然现在也可以正常工作;但是第二种方式是MyBatis官方所推荐使用的,其表达方式也更加直白,代码更加清晰,类型安全,也不用担心易错的字符串字面值以及强制类型转换。

本文深入介绍了MyBatis框架的三大核心对象:SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession,详细解析了它们的作用、生命周期及使用方式。
809

被折叠的 条评论
为什么被折叠?



