Mybatis 的连接池技术
- Mybatis 连接池的分类
- UNPOOLED 不使用连接池的数据源
- POOLED 使用连接池的数据源
- JNDI 使用 JNDI 实现的数据源
- 说明
- PooledDataSource 和 UnPooledDataSource 都实现了 java.sql.DataSource
- PooledDataSource 持有一个 UnPooledDataSource 的引用
- 当 PooledDataSource 需要创建 java.sql.Connection 实例对象时,还是通过 UnPooledDataSource 来创建,PooledDataSource 只是提供一种缓存连接池机制
- 图示(连接池根本上就是一个集合)
Mybatis 中数据源的配置
<!--
MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED”:MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
分析 Mybatis 中 DataSource 的存取(了解)
- 分析:
MyBatis 是通过工厂模式来创建数据源 DataSource 对象的, MyBatis 定义了抽象的工厂接口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源 DataSource - 原码
- MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中,供以后使用
- 先进入 XMLConfigBuilder 类中,可以找到如下代码:
分析 Mybatis 中连接的获取过程(了解)
@Test
public void testSql() throws Exception {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("findUserById", 41);
System.out.println(list.size());
}
- 当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象 来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候,只有当第 4句 sqlSession.selectList(“findUserById”),才会触发 MyBatis 在底层执行下面这个方法来创建 java.sql.Connection 对象
- 原码
- 执行流程图
- 真正连接打开的时间点,只是在我们执行 SQL 语句时,才会进行。其实这样做我们也可以进一步发现,数据库连接是我们最为宝贵的资源,只有在要用到的时候,才去获取并打开连接,当我们用完了就再立即将数据库连接归还到连接池中
Mybatis 的事务控制
JDBC 中事务管理
Mybatis 手动提交事务
@Before
public void init() throws Exception {
//读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 创建SessionFactory工厂
builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
// 使用工厂生产SqlSession对象
sqlSession = factory.openSession();
// 使用SqlSession创建Dao接口的代理对象
iUserDao = sqlSession.getMapper(IUserDao.class);
}
@After
public void destory() throws Exception {
sqlSession.commit();
sqlSession.close();
in.close();
}
@Test
public void saveUser() {
User user = new User();
user.setUsername("modify User property");
user.setAddress("北京市顺义区");
user.setSex("男");
user.setBirthday(new Date());
System.out.println(user);
iUserDao.saveUser(user);
System.out.println(user);
}
- 在CUD操作过程中,我们需要手动的进行事务的提交,因为在连接池取出的连接都调用了 connection.setAutoCommit(false) 方法,这样我们 就必须使用 sqlSession.commit() 方法,相当于使用了 JDBC 中的 connection.commit() 方法实现事务提交
- 原码
Mybatis 自动提交事务
- 将 session = factory.openSession(); 改为 session = factory.openSession(true); 即可
- 原码
- 设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交