7-Mybatis 连接池与事务深入

、Mybatis 的连接池技术

我们在前面的 WEB 课程中也学习过类似的连接池技术,而在 Mybatis 中也有连接池技术,但是它采用的是自
己的连接池技术。在 Mybatis SqlMapConfig.xml 配置文件中,通过 来实
Mybatis 中连接池的配置。

1.Mybatis 数据源的分类

可以看出 Mybatis 将它自己的数据源分为三类:
 
UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用 JNDI 实现的数据源
 
具体结构如下:

7-Mybatis 连接池与事务深入_第1张图片

相应地, MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource
PooledDataSource 类来表示 UNPOOLED POOLED 类型的数据源。
 
7-Mybatis 连接池与事务深入_第2张图片
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据
库连接,也就是我们所说的连接池技术)。

2.SqlMapConfig.xml 中数据源的配置

 
 



MyBatis 在初始化时,根据 type 属性来创建相应类型的的数据源 DataSource ,即:
type=”POOLED” MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI” MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

3.Mybatis DataSource 的存取

MyBatis 是 通 过 工 厂 模 式 来 创 建 数 据 源 DataSource 对 象 的 , MyBatis 定 义 了 抽 象 的 工 厂 接
:org.apache.ibatis.datasource.DataSourceFactory, 通过其 getDataSource() 方法返回数据源DataSource
 
下面是 DataSourceFactory 源码,具体如下:
package org.apache.ibatis.datasource;
import java.util.Properties;
import javax.sql.DataSource;
/**
* @author Clinton Begin
*/
public interface DataSourceFactory {
 void setProperties(Properties props);
 DataSource getDataSource();
}
MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中, 供以后使用。
具体分析过程如下:
a. 先进入 XMLConfigBuilder 类中,可以找到如下代码:
 
7-Mybatis 连接池与事务深入_第3张图片
b. 分析 configuration 对象的 environment 属性,结果如下:
7-Mybatis 连接池与事务深入_第4张图片

4.Mybatis 中连接的获取过程分析

当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象
来创建 java.sql.Connection 对象。也就是说, java.sql.Connection 对象的创建一直延迟到执行 SQL 语句
的时候。
@Test
public void testSql() throws Exception {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
List list = sqlSession.selectList("findUserById",41);
System.out.println(list.size());
}
只有当第 4 sqlSession.selectList(" findUserById ") ,才会触发 MyBatis 在底层执行下面这个方
法来创建 java.sql.Connection 对象。
如何证明它的加载过程呢?
我们可以通过断点调试,在 PooledDataSource 中找到如下 popConnection() 方法,如下所示:
 
7-Mybatis 连接池与事务深入_第5张图片
 
分析源代码,得出 PooledDataSource 工作原理如下:
7-Mybatis 连接池与事务深入_第6张图片
 
下面是连接获取的源代码:
7-Mybatis 连接池与事务深入_第7张图片
最后我们可以发现,真正连接打开的时间点,只是在我们执行 SQL 语句时,才会进行。其实这样做我们也可以
进一步发现,数据库连接是我们最为宝贵的资源,只有在要用到的时候,才去获取并打开连接,当我们用完了就再
立即将数据库连接归还到连接池中。
 

二、Mybatis 的事务控制

1.JDBC 中事务的回顾

JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit() 方法就可以调整。
通过 JDK 文档,我们找到该方法如下:
7-Mybatis 连接池与事务深入_第8张图片
 
7-Mybatis 连接池与事务深入_第9张图片
那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC
setAutoCommit() 方法来设置事务提交方式的。

2.Mybatis 中事务提交方式

Mybatis 中事务的提交方式,本质上就是调用 JDBC setAutoCommit()来实现事务控制。

 @Test
    public void testSave() {
        User user = new User();
        user.setUserName("小王 新");
        user.setAddress("北京市顺义区");
        user.setSex("男");
        user.setBirthday(new Date(System.currentTimeMillis()));
        System.out.println("保存操作之前:" + user);
        //5.执行保存方法
        userDao.saveUser(user);
        System.out.println("保存操作之后:" + user);
    }

7-Mybatis 连接池与事务深入_第10张图片

这是我们的 Connection 的整个变化过程,通过分析我们能够发现之前的 CUD 操作过程中,我们都要手动进
行事务的提交,原因是 setAutoCommit() 方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,
必须通过 sqlSession.commit() 方法来执行提交操作。

3.Mybatis 自动提交事务的设置

通过上面的研究和分析,现在我们一起思考,为什么 CUD 过程中必须使用 sqlSession.commit() 提交事
务?主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false) 方法,这样我们
就必须使用 sqlSession.commit() 方法,相当于使用了 JDBC 中的 connection.commit() 方法实现事务提
交。
明白这一点后,我们现在一起尝试不进行手动提交,一样实现 CUD 操作。
@Before//在测试方法执行之前执行
public void init() throws Exception {
    //1.读取配置文件
    in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.创建构建者对象
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //3.创建 SqlSession 工厂对象
    factory = builder.build(in);
    //4.创建 SqlSession 对象
    session = factory.openSession(true);
    //5.创建 Dao 的代理对象
    userDao = session.getMapper(IUserDao.class);
}

@After//在测试方法执行完成之后执行
public void destroy() throws Exception {
    //session.commit();
    //7.释放资源
    session.close();
    in.close();
}
所对应的 DefaultSqlSessionFactory 类的源代码:
7-Mybatis 连接池与事务深入_第11张图片
运行测试保存方法,结果如下
7-Mybatis 连接池与事务深入_第12张图片
我们发现,此时事务就设置为自动提交了,同样可以实现 CUD 操作时记录的保存。虽然这也是一种方式,但就
编程而言,设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务
情况来决定提交是否进行提交。

你可能感兴趣的:(mybatis)