![Java EE轻量级框架应用实战:SSM框架(Spring MVC+Spring+MyBatis)](https://wfqqreader-1252317822.image.myqcloud.com/cover/921/32517921/b_32517921.jpg)
2.1 MyBatis框架的核心接口和类
使用MyBatis框架对项目进行测试时,创建SqlSession对象的代码如下。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_1.jpg?sign=1739287214-sNlyP0c0xTa4z6aILsfE1p1ZMTSvOVqa-0-465d5ed1f19a6c8bcdd4c44cacdc8e9c)
代码中涉及两个核心对象:SqlSessionFactory和SqlSession,它们在MyBatis框架中起着至关重要的作用。本节将对这两个对象进行详细讲解。首先介绍MyBatis框架的核心接口和类,如图2.1所示。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_2.jpg?sign=1739287214-1i4g00RMQQa8trkNjycT9otGOrKzfJds-0-0863c34b782f6b28b5d5f58c79adaa86)
图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所示。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_3.jpg?sign=1739287214-iKUkAWPybt4NyajLjXpv584WMyaZaQzw-0-c6d7c235582e04a02657fcd60eb3e2e6)
图2.2 SqlSessionFactoryBuilder提供的build()方法
通过源码分析,可以发现它们都在调用同一签名方法:
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_4.jpg?sign=1739287214-pfbREvIn9pUsUK7U5waS42bJ7OO0t6Ca-0-ed93bed032f2042dccb5e147a6604fdb)
由于方法参数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所示。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_5.jpg?sign=1739287214-PldeIQBfWEpgtMAckgnqQ6zehSvUSA4i-0-710b60f833448f1dd0e2b1a596ecb53d)
图2.3 SqlSessionFactory提供的openSession()方法
当openSession()方法的参数为boolean值时,若传入true则表示关闭事务控制,自动提交;若传入false则表示开启事务控制。若不传入参数则默认为true。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_7.jpg?sign=1739287214-EvkXJKZuvpZwKj47NzK60fFkBWEqKIz2-0-9dabbc34879a90bec9eb9db7419f23e6)
2.SqlSessionFactory的生命周期和作用域
SqlSessionFactory一旦创建就会在整个应用运行过程中始终存在,没有理由销毁或再创建,并且在应用运行中也不建议多次创建SqlSessionFactory。因此SqlSessionFactory的最佳作用域就是Application,即随着应用的生命周期一同存在。那么这种“存在于整个应用运行期间,并且同时只存在一个对象实例”的模式就是单例模式(指在应用运行期间有且仅有一个实例)。
下面将对获取SqlSessionFactory的代码进行优化,最简单的实现方式就是放在静态代码块下,以保证SqlSessionFactory只被创建一次,其实现步骤如下。
(1)创建工具类MyBatisUtil.java,在静态代码块中创建SqlSessionFactory。
在前面的案例中,每个方法执行时都需要读取配置文件,并根据配置文件的信息构建SqlSessionFactory,然后再创建SqlSession,这就导致了大量的重复代码。为了简化开发,可以先将上述重复代码封装到一个工具类中,然后通过工具类来创建SqlSession,其代码见示例1。
【示例1】 工具类MyBatisUtil.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_9.jpg?sign=1739287214-BI43OjIhLdNy6ptZ2nSxorwms1wopxfF-0-61ae051840430ef69dd511913159615f)
(2)创建 SqlSession和关闭SqlSession,其代码见示例2。
【示例2】 创建SqlSession和关闭SqlSession
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_11.jpg?sign=1739287214-Qe4ge0tJIjF840N7osLor4AAVhd6pGyH-0-3d83d8b2ae58f3066858e622ca36d665)
通过以上静态类的方式来保证SqlSessionFactory实例只能被创建一次。当然,最佳的解决方案是使用依赖注入容器—Spring框架来管理SqlSessionFactory的单例生命周期。
设计模式中的单例模式将在后续的Spring MVC中具体展开讲解,此处了解即可。
2.1.3 SqlSession
1.SqlSession的作用
SqlSession是用于执行持久化操作的对象,类似于JDBC的Connection。它提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句,SqlSession提供的方法如图2.4所示。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_13.jpg?sign=1739287214-upuVFDre2cwhJP9YOkIgkDCWNrMV8JaZ-0-9c488f1988a0f3b32531686614db2d03)
图2.4 SqlSession提供的方法
2.SqlSession的生命周期和作用域
SqlSession对应着一次数据库会话,由于数据库会话不是永久的,因此SqlSession的生命周期也不是永久的。相反,在每次访问数据库时都需要创建它(并不是在SqlSession里只能执行一次SQL,是完全可以执行多次的,但若关闭SqlSession则需要重新创建)。创建SqlSession的地方只有一个,就是SqlSessionFactory对象的openSession()方法。
每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。因此最佳的范围是在request作用域或方法体作用域内。
关闭SqlSession是非常重要的,必须确保SqlSession在finally语句块中正常关闭。关闭的标准方式如下。
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_15.jpg?sign=1739287214-ITvSiZKRwfukEkpzsuQdaWks33T7Q48K-0-c0ced7dc33cbe3809a23e46e2f37e281)
3.SqlSession的常用方法
SqlSession中包含了很多方法,其常用方法及其说明如表2-1所示。
表2-1 SqlSession的常用方法及其说明
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_16.jpg?sign=1739287214-Ed9HAJmguDvhu5c9dCux3rPM8H1tECXP-0-e3ebd9ae6c38026b02a37db74fd84b90)
续表
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_17.jpg?sign=1739287214-eYctvWj1GyuTFKju9d0Cuhnj5KHaXaAt-0-9a86bc36ea88ce9a33d6fd389a50e629)
4.SqlSession的两种使用方式
(1)通过SqlSession实例直接执行已映射的SQL语句。
如通过调用selectList方法执行用户表的查询操作,其步骤如下。
修改UserMapper.xml文件,增加查询用户列表的select节点,见示例3。
【示例3】 增加查询用户列表的select节点
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_19.jpg?sign=1739287214-Mpxz53xdtxJOz8daRV8VvgzCdRUof1O9-0-63e70259a1f8c8381e711672be38ed6e)
修改测试类UserMapperTest.java,并调用selectList方法执行查询操作,见示例4。
【示例4】 调用selectList方法执行查询操作
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_21.jpg?sign=1739287214-zXnCpVCNA7rTAmV3LOw8OBYHwErGbQqL-0-88a83d7f5a40e6a6db0ea1a00aba4429)
(2)基于Mapper接口方式操作数据。
修改上一个演示示例,其步骤如下。
创建绑定映射语句的UserMapper.java接口,并提供getUserList()接口方法,该接口称为映射器,见示例5。
接口的方法必须与SQL映射文件中SQL语句的id相对应。
【示例5】 UserMapper.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_24.jpg?sign=1739287214-oWDcpzN2DTD0L4qLFslxD9vb5dgLbaLQ-0-41dc8c7545cc8777ffa85fff35acc465)
修改测试类UserMapperTest.java,并调用getMapper(Mapper.class)执行Mapper接口方法实现对数据的查询操作,其代码见示例6。
【示例6】 UserMapperTest.java
![img](https://epubservercos.yuewen.com/1B1F03/17545850907267806/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1739287214-Jv5KdTciaMYjagCOEFQHWUNd8kSgulgy-0-6672bdac3ba9d4706f472d79df1e341b)
第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,按照两种方式分别实现对数据的操作,并在后台运行输出结果。