mybatis学习——Mybatis 连接池与事务深入
Mybatis 的连接池技术
在 Mybatis 的 SqlMapConfig.xml 配置文件中,通过<dataSource type=”pooled”>来实现 Mybatis 中连接池的配置。
1.1 Mybatis 连接池的分类
在 Mybatis 中我们将它的数据源 dataSource 分为以下几类:
可以看出 Mybatis 将它自己的数据源分为三类:
UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用 JNDI 实现的数据源
具体结构如下:
相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource, PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源。
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据 库连接,也就是我们所说的连接池技术)。
1.2 连接池的概念
由于每次新建连接比较耗时,所以一开始就新建好n个连接(n≤max,max为连接池设定的最大连接数),这些连接没有被使用的时候就在空闲池里。在使用连接时有三种情况:
1.当空闲池中有连接时,就从空闲池里拿出一个,放到活动池里进行使用。
2.当空闲池里没有空闲连接时,就看活动池中使用的连接的数量是否达到max,如果没有,则就创建一个新的连接放入活动池中使用。
3.若活动池中的连接也达到设定的max值,则就将活动池中最老的连接进行配置修改,从而变为最新的连接投入使用。
注意: 1.空闲池和活动池实际上就是两个队列。
2.在一个连接使用完后,就会从活动区归还到空闲区。
3.连接池就是用于存储连接的一个容器。
4.容器就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一个连接。
5.该集合必须实现一个队列的特性:先进先出
1.3 Mybatis 中数据源的配置
MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即: type=”POOLED”:MyBatis 会创建 PooledDataSource 实例 type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例 type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
Mybatis 的事务控制
2.1 JDBC 中事务的回顾
在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法就可以调整。 通过 JDK 文档,我们找到该方法如下:
那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC的 setAutoCommit()方法来设置事务提交方式的。
2.2 Mybatis 中事务提交方式
Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制。
我们运行之前所写的代码:
public class MybatisCRUDTest { private InputStream in; private SqlSessionFactory factory; private SqlSession session; private IUserDao userDao; @Test public void testFindOne(){ //6.执行操作 User user = userDao.findById(41); System.out.println(user); } ........ @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(); //5.创建Dao的代理对象 userDao = session.getMapper(IUserDao.class); } @After//测试方法执行完成之后执行 public void destroy() throws Exception{ //7.提交事务 session.commit(); //8.释放资源 session.close(); in.close(); } }
观察在它在控制台输出的结果:
通过分析我们能够发现之前的 CRUD 操作过程中,我们都要手动进 行事务的提交,原因是 setAutoCommit()方法,在执行时的值被设置为 false 了,所以我们在 CRUD 操作中, 必须通过 sqlSession.commit()方法来执行提交操作。
2.3 Mybatis 自动提交事务的设置
通过上面的研究和分析,现在我们一起思考,为什么 CRUD 过程中必须使用 sqlSession.commit()提交事 务?主要原因就是在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们 就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提 交。
明白这一点后,我们现在一起尝试不进行手动提交,一样实现 CRUD 操作。
public class MybatisCRUDTest { private InputStream in; private SqlSessionFactory factory; private SqlSession session; private IUserDao userDao; @Test public void testFindOne(){ //6.执行操作 User user = userDao.findById(41); System.out.println(user); } ........ @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{ //7.提交事务 //session.commit(); //8.释放资源 session.close(); in.close(); } }
session = factory.openSession(true);该语句传入参数 true 即可。
运行的结果如下:
我们发现,此时事务就设置为自动提交了,同样可以实现CRUD操作时记录的保存。虽然这也是一种方式,但就 编程而言,设置为自动提交方式为 false再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务 情况来决定提交是否进行提交。