JavaWeb——MyBatis框架之连接池原理、MyBatis事务提交设置、动态SQL语法总结

时间:2022-07-25
本文章向大家介绍JavaWeb——MyBatis框架之连接池原理、MyBatis事务提交设置、动态SQL语法总结,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本次博文包括比较零散的MyBatis内容,包括MyBatis的连接池、事务和动态SQL语句的用法。

1 MyBatis连接池

实际开发中都会使用连接池,因为可以减少获取连接消耗的时间,连接池就是用来存储连接的一个容器,通常用一个集合对象表示,该集合必须是线程安全的,不能两个线程拿到同一个连接,该集合还必须实现队列的特性,先进先出。

MyBatis连接池的配置有3种方式,在主配置文件SqlMapConfig.xml的dataSource标签配置,其中type属性表示了采用了哪种连接池方式:

  • 1)POOLED:传统的javax.sql.DataSource规范中的连接池,MyBatis有规范的实现;
  • 2)UNPOOLED:传统的获取连接的方式,也实现了javax.sql.DataSource接口,但没有使用池的思想,每次用都是重新获取连接;
  • 3)JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同服务器能拿到的DataSource不同。需要注意的是,这种方式若不是web或maven的war工程,是不能使用的。如Tomcat服务器采用的是dbcp连接池。

1.1 UNPOOLED配置连接池的原理

我们使用上一博文的工程为基础进行演示分析,首先把SqlMapConfig.xml的dataSource标签的type属性取值为POOLED,运行测试类中的testFindAll方法,观察打印输出的信息:

再把SqlMapConfig.xml的dataSource标签的type属性取值为UNPOOLED,运行测试类中的testFindAll方法,观察打印输出的信息:

以上对比,我们可以知道,在使用UNPOOLED时,是直接创建连接的,用完后就关闭了,没有池子。

实际上UNPOOLED和POOLED分别对应的类是UnpooledDataSource和PooledDataSource,我们在在IDEA中打开UnpooledDataSource类,一路跟踪方法,可以发现这个原理:

getConnection()方法->doGetConnection()方法->doGetConnection():

1.2 POOLED配置连接池的原理

打开PooledDataSource类,一路跟踪方法:getConnection()->popConnection():

我们实际开发中一般都是使用POOLED。

2 MyBatis的事务

关于事务,不做过多说明了,可以参照下之前的博文。MyBatis中的事务是通过SqlSession对象的commit方法和rollback方法实现事务的提交和回滚。在上一博文中,我们对数据库的增删改查操作发现,必须使用sqlSession.commit()方法提交事务,原因是什么呢?

那是因为从连接池取出的连接都会调用connection.setAutoCommit(false)方法关闭自动提交事务,这一点从打印的信息就可以验证:

所以,要想不进行手动提交事务,是可以设置的,在此处设置为true即可:

【注意】:设置自动提交事务,这种在实际开发中也是不常用的,因为每一次操作数据库都要提交一次事务,这会加大开销,最明显的例子就是往数据库中批量插入数据时,每次都提交一次事务的话,插入速度是很慢的。

3 MyBatis的动态SQL用法

由上一博文我们熟悉了使用MyBatis的CRUD简单操作,但是我们发现操作的输入条件都比较单一,或者是指定id查询的、或者是查询所有的、或者是根据用户名模糊查询的,那要是实际业务中涉及到查询条件比较复杂的场景该怎么办?所以,这里就用到了动态SQL。

3.1 if标签的使用

if标签在多条件组合查询中比较常用,根据实体类的不同取值,使用不同的sql语句查询,以一个具体的例子看下用法:

1)用户接口中添加 根据输入的参数条件查询 方法:

//用户持久层接口
public interface UserDao {
    //根据输入的参数条件查询,user就是查询的条件,可能只有其中一个属性,也可能都有或都没有
    List<User> findUserByCondition(User user);
}

2)用户映射配置文件中配置,注意if的写法格式,其中的1个条件内的组合用 and连接(不能用&&),有多个条件就用多个if标签

<!--    根据条件查询-->
    <select id="findUserByCondition" parameterType="com.winter.domain.User" resultType="com.winter.domain.User">
        select *from user where 1=1
        <if test="username != null and username != ''">
            and username LIKE #{username}
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
    </select>

3)测试类中进行测试:查询姓名中包含“王”的女性用户

    //测试使用动态sql查询
    @Test
    public void testFindByCondition(){
        User user = new User();
        user.setUsername("%王%");
        user.setSex("女");
        List<User> users = userDao.findUserByCondition(user);
        for (User user1 : users) {
            System.out.println(user1);
        }
    }

3.2 where标签的使用

上述if标签 select * from user 后要加个条件whre 1=1,这个就是让其永远为真,理解起来挺另类的,所以可以使用where标签,更直观些,使用起来比较方便,就是将if内的条件用where标签包裹起来,映射配置文件中修改如下:

<!--    根据条件查询-->
    <select id="findUserByCondition" parameterType="com.winter.domain.User" resultType="com.winter.domain.User">
        select *from user
        <where>
            <if test="username != null and username != ''">
                and username LIKE #{username}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
        </where>
    </select>

3.3 foreach标签的使用

若我们要查询多个指定id用户信息该怎么办?SQL语句是很容易写的:select * from user where id in(1,2),但是在MyBatis映射配置文件中如何传递参数呢? 这时候就用到了foreach标签,其就是来遍历集合的,属性如下:

collection

要遍历的集合元素

open

语句的开始部分

close

语句结束部分

item

遍历集合的每个元素,生产的变量,可以自定义,但要和#{}中的保持一致

sperator

分隔符

1)QueryVo类中添加ids List集合;

2)用户接口中添加 根据QueryVo的id集合查询用户 方法:

public interface UserDao {
    //根据QueryVo的id集合查询用户
    List<User> findUserInIds(QueryVo vo);
}

3)用户映射配置文件中配置,注意foreach的写法格式,注意item 属性名要和 #{}中的保持一致;

<select id="findUserInIds" parameterType="com.winter.domain.QueryVo" resultType="com.winter.domain.User">
        select * from user
        <where>
            <if test="ids != null and ids.size()>0">
                <foreach collection="ids" open="and id in(" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>

4)测试类中进行测试:查询id为1和2 的用户信息

    //测试使用QueryVo作为查询条件
    @Test
    public void testFindUserInIds(){
        QueryVo vo = new QueryVo();
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        vo.setIds(ids);
        //5.执行查询
        List<User> users = userDao.findUserInIds(vo);
        for (User user1 : users) {
            System.out.println(user1);
        }
    }

需要源码的传送门在此

———————————————————————————————————

本文为博主原创文章,转载请注明出处!