2.1 MyBatis框架的核心接口和类
使用MyBatis框架对项目进行测试时,创建SqlSession对象的代码如下。
代码中涉及两个核心对象:SqlSessionFactory和SqlSession,它们在MyBatis框架中起着至关重要的作用。本节将对这两个对象进行详细讲解。首先介绍MyBatis框架的核心接口和类,如图2.1所示。
图2.1 MyBatis框架的核心接口和类
(1)每个MyBatis框架的应用程序都以一个SqlSessionFactory对象的实例为核心。
(2)获取SqlSessionFactoryBuilder对象,可根据XML配置文件或Configuration类的实例构建该对象。
(3)获取SqlSessionFactory对象,可以通过SqlSessionFactoryBuilder对象来获得。
(4)获取SqlSession实例,SqlSession对象包含以数据库为背景的所有执行SQL操作的方法,可以使用该实例直接执行已映射的SQL语句。
2.1.1 SqlSessionFactoryBuilder
1.SqlSessionFactoryBuilder的作用
SqlSessionFactoryBuilder负责构建SqlSessionFactory,并提供多个build()方法的重载,如图2.2所示。
图2.2 SqlSessionFactoryBuilder提供的build()方法
通过源码分析,可以发现它们都在调用同一签名方法:
由于方法参数environment和properties都可以为null,那么真正的重载方法只有如下3种。
(1)build(Reader reader,String environment,Properties properties)。
(2)build(InputStream inputStream,String environment,Properties properties)。
(3)build(Configuration config)。
通过上述分析发现,配置信息提供给SqlSessionFactoryBuilder的build()方法,包括InputStream(字节流)、Reader(字符流)和Configuration(类),由于字节流与字符流都属于读取配置文件的方式,所以从配置信息的来源就很容易想到构建一个SqlSessionFactory的两种方式:读取XML配置文件和编程。本章采用读取XML配置文件的方式。
2.SqlSessionFactoryBuilder的生命周期和作用域
SqlSessionFactoryBuilder的最大特点是用过即丢。一旦创建SqlSessionFactory后,这个类就不再需要了,因此SqlSessionFactoryBuilder的最佳范围就是存在于方法体内,也就是局部变量。
2.1.2 SqlSessionFactory
1.SqlSessionFactory的作用
SqlSessionFactory就是创建SqlSession实例的工厂,所有的MyBatis框架应用都以SqlSessionFactory实例为中心。SqlSessionFactory实例可以通过SqlSessionFactoryBuilder来获得,然后就可以使用openSession()方法来获取SqlSession实例,如图2.3所示。
图2.3 SqlSessionFactory提供的openSession()方法
当openSession()方法的参数为boolean值时,若传入true则表示关闭事务控制,自动提交;若传入false则表示开启事务控制。若不传入参数则默认为true。
2.SqlSessionFactory的生命周期和作用域
SqlSessionFactory一旦创建就会在整个应用运行过程中始终存在,没有理由销毁或再创建,并且在应用运行中也不建议多次创建SqlSessionFactory。因此SqlSessionFactory的最佳作用域就是Application,即随着应用的生命周期一同存在。那么这种“存在于整个应用运行期间,并且同时只存在一个对象实例”的模式就是单例模式(指在应用运行期间有且仅有一个实例)。
下面将对获取SqlSessionFactory的代码进行优化,最简单的实现方式就是放在静态代码块下,以保证SqlSessionFactory只被创建一次,其实现步骤如下。
(1)创建工具类MyBatisUtil.java,在静态代码块中创建SqlSessionFactory。
在前面的案例中,每个方法执行时都需要读取配置文件,并根据配置文件的信息构建SqlSessionFactory,然后再创建SqlSession,这就导致了大量的重复代码。为了简化开发,可以先将上述重复代码封装到一个工具类中,然后通过工具类来创建SqlSession,其代码见示例1。
【示例1】 工具类MyBatisUtil.java
(2)创建 SqlSession和关闭SqlSession,其代码见示例2。
【示例2】 创建SqlSession和关闭SqlSession
通过以上静态类的方式来保证SqlSessionFactory实例只能被创建一次。当然,最佳的解决方案是使用依赖注入容器—Spring框架来管理SqlSessionFactory的单例生命周期。
设计模式中的单例模式将在后续的Spring MVC中具体展开讲解,此处了解即可。
2.1.3 SqlSession
1.SqlSession的作用
SqlSession是用于执行持久化操作的对象,类似于JDBC的Connection。它提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句,SqlSession提供的方法如图2.4所示。
图2.4 SqlSession提供的方法
2.SqlSession的生命周期和作用域
SqlSession对应着一次数据库会话,由于数据库会话不是永久的,因此SqlSession的生命周期也不是永久的。相反,在每次访问数据库时都需要创建它(并不是在SqlSession里只能执行一次SQL,是完全可以执行多次的,但若关闭SqlSession则需要重新创建)。创建SqlSession的地方只有一个,就是SqlSessionFactory对象的openSession()方法。
每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。因此最佳的范围是在request作用域或方法体作用域内。
关闭SqlSession是非常重要的,必须确保SqlSession在finally语句块中正常关闭。关闭的标准方式如下。
3.SqlSession的常用方法
SqlSession中包含了很多方法,其常用方法及其说明如表2-1所示。
表2-1 SqlSession的常用方法及其说明
续表
4.SqlSession的两种使用方式
(1)通过SqlSession实例直接执行已映射的SQL语句。
如通过调用selectList方法执行用户表的查询操作,其步骤如下。
修改UserMapper.xml文件,增加查询用户列表的select节点,见示例3。
【示例3】 增加查询用户列表的select节点
修改测试类UserMapperTest.java,并调用selectList方法执行查询操作,见示例4。
【示例4】 调用selectList方法执行查询操作
(2)基于Mapper接口方式操作数据。
修改上一个演示示例,其步骤如下。
创建绑定映射语句的UserMapper.java接口,并提供getUserList()接口方法,该接口称为映射器,见示例5。
接口的方法必须与SQL映射文件中SQL语句的id相对应。
【示例5】 UserMapper.java
修改测试类UserMapperTest.java,并调用getMapper(Mapper.class)执行Mapper接口方法实现对数据的查询操作,其代码见示例6。
【示例6】 UserMapperTest.java
第1种方式是MyBatis旧版本提供的操作方式,虽然现在也可以正常工作,但第2种方式是MyBatis官方推荐使用的,其表达方式的代码更清晰且类型安全,不用担心易错的字符串字面值和强制类型转换。
2.1.4 技能训练
上机练习1 实现供应商表的查询
需求说明
在第1章练习搭建的环境中,完成以下操作。
(1)使用MyBatis框架实现对供应商表的查询操作(查询出全部数据)。
(2)编写工具类MyBatisUtil.java,获取SqlSessionFactory实例。
(3)分别使用两种方式(①通过SqlSession实例直接运行已映射的SQL语句;②基于Mapper接口方式操作数据)实现对数据的操作,并对比其区别。
(1)修改SQL映射文件ProviderMapper.xml,增加select元素节点,编写查询语句。
(2)编写MyBatisUtil.java,在静态代码块中实现SqlSessionFactory的创建,并在该类中增加创建SqlSession和关闭SqlSession的静态方法。
(3)创建绑定映射语句的Mapper接口:ProviderMapper.java。
(4)修改测试类ProviderMapperTest.java,按照两种方式分别实现对数据的操作,并在后台运行输出结果。