一,Mybatis 连接池与事务深入
1.1 Mybatis 的连接池技术
Mybatis 中连接池技术,它采用的是自己的连接池技术。在 Mybatis 的 SqlMapConfig.xml 配置文件中,通过来实现 Mybatis 中连接池的配置。
1.1.1 Mybatis 连接池的分类
在 Mybatis 中我们将它的数据源 dataSource 分为以下几类:
可以看出 Mybatis 将它自己的数据源分为三类:
UNPOOLED
不使用连接池的数据源POOLED
使用连接池的数据源JNDI
使用 JNDI 实现的数据源
具体结构如下:
相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource,PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源。
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。
1.1.2 Mybatis 中数据源的配置
MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即:
- type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
- type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
- type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
我们的数据源配置就是在 SqlMapConfig.xml 文件中,具体配置如下:
1.2 Mybatis 的事务控制
1.2.1 JDBC 中事务的回顾
在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法就可以调整。
通过 JDK 文档,我们找到该方法如下:
那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的setAutoCommit()方法来设置事务提交方式的。
1.2.2 Mybatis 中事务提交方式
Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制。
我们运行之前所写的代码:
@Test public void testSaveUser() throws Exception { User user = new User(); user.setUsername("mybatis user09"); //6.执行操作 int res = userDao.saveUser(user); System.out.println(res); System.out.println(user.getId()); } @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(); }
默认 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过 sqlSession.commit()方法来执行提交操作。
1.2.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{ //7.释放资源 session.close(); in.close(); }
事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。虽然这也是一种方式,但就编程而言,设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。
二.Mybatis 的动态 SQL 语句
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL 是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
参考的官方文档,描述如下:
2.1 动态 SQL 之标签
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
2.1.1 持久层 Dao 接口
/** * 根据用户信息,查询用户列表 * @param user * @return */ ListfindByUser(User user);
2.1.2 持久层 Dao 映射配置
注意:
另外要注意 where 1=1 的作用~!
2.1.3 测试
@Test public void testFindByUser() { User u = new User(); u.setUsername("%王%"); u.setAddress("%顺义%"); //6.执行操作 Listusers = userDao.findByUser(u); for(User user : users) { System.out.println(user); } }
2.2 动态 SQL 之标签
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。
2.2.1 持久层 Dao 映射配置
2.3 动态标签之标签
需求
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE ‘%张%' AND (id =10 OR id =89 OR id=16) SELECT * FROM USERS WHERE username LIKE ‘%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。
这样我们将如何进行参数的传递?
2.3.1 在 QueryVo 中加入一个 List 集合用于封装参数
/** * *Title: QueryVo
*Description: 查询的条件
*Company: http://www.itheima.com/
*/ public class QueryVo implements Serializable { private Listids; public List getIds() { return ids; } public void setIds(List ids) { this.ids = ids; } }
2.3.2 持久层 Dao 接口
/** * 根据 id 集合查询用户 * @param vo * @return */ ListfindInIds(QueryVo vo);
2.3.3 持久层 Dao 映射配置
SQL 语句:
select 字段 from user where id in (?)
collection
:代表要遍历的集合元素,注意编写时不要写#{}open
:代表语句的开始部分close
:代表结束部分item
:代表遍历集合的每个元素,生成的变量名sperator
:代表分隔符
2.3.4 编写测试方法
@Test public void testFindInIds() { QueryVo vo = new QueryVo(); Listids = new ArrayList (); ids.add(41); ids.add(42); ids.add(43); ids.add(46); ids.add(57); vo.setIds(ids); //6.执行操作 List users = userDao.findInIds(vo); for(User user : users) { System.out.println(user); } }
2.4 Mybatis 中简化编写的 SQL 片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。
2.4.1 定义代码片段
select * from user
2.4.2 引用代码片段
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。