MyBatis进阶(一)连接池 & 事务提交 & 动态 SQL 语句 & 延迟加载 & 缓存

MyBatis

Mybatis 的连接池技术

1.1MyBatis连接池分类

在 Mybatis 中我们将它的数据源 dataSource 分为以下几类,
在这里插入图片描述

可以看出 Mybatis 将它自己的数据源分为三类:

JNDI 使用 JNDI 实现的数据源

POOLED 使用连接池的数据源

UNPOOLED 不使用连接池的数据源

在这里插入图片描述
相应地,MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource, PooledDataSource 类来表示 UNPOOLED、POOLED 类型的数据源,并且PooledDataSource 还持有一个UnpooledDataSource 的引用。当PooledDataSource 需要创建java.sql.Connection实例对象时,还是通过调用UnpooledDataSource来创建。PooledDataSource只是一种缓存连接池机制。

在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。

1.2Mybatis 中数据源的配置

主配置文件如下

<!-- 配置数据源(连接池)信息 --> 
<dataSource type="POOLED">  
    <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> 
<!-- type=POOLED时,MyBatis 会创建 PooledDataSource 实例  --> 

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,type=POOLED时,MyBatis 会创建 PooledDataSource 实例。

1.3Mybatis 中 DataSource 的存取

MyBatis 是通过工厂模式来创建数据源 DataSource 对象的, MyBatis 定义了抽象的工厂接 口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源 DataSource。

1.4MyBatis中连接获取的过程

当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。数据库连接是我们最为宝贵的资源,只有在要用到的时候,才去获取并打开连接,当我们用完了就再立即将数据库连接归还到连接池中。

Mybatis 的事务提交

在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit() 方法就可以调整。 Mybatis框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC的 setAutoCommit()方法来设置事务提交方式的。
观察Connection 的整个变化过程,通过分析我们能够发现之前的 CRUD 操作过程中,我们都要手动进行事务的提交,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CRUD 操作中, 必须通过 sqlSession.commit() 方法来执行提交操作,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。

可以在创建sqlSession对象时指定自动提交 session = factory.openSession(true);

但就编程而言,设置为自动提交方式为 false再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。

Mybatis 的动态 SQL 语句

<!-- 查询所有用户在 id 的集合之中 -->  
<select id="findInIds" resultType="user" parameterType="queryvo">  
    <!--  select * from user where id in (1,2,3,4,5); --> 
  	<include refid="defaultSql"></include>   
  	<where> 
  		<if test="ids != null and ids.size() > 0">     
       		<foreach collection="ids" open="id in ( " close=")" item="uid"  separator=",">      
           		#{uid}     
       		</foreach>   
    	</if>   
    </where>  
</select> 

SQL片段

<sql id="defaultSql">   
	select * from user  
</sql> 
<select id="findAll" resultType="user">  
    <include refid="defaultSql"></include> 
</select> 

MyBatis延迟加载

延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降

使用了resultMap来实现一对一,一对多,多对多关系的操作。主要 是通过 association、collection 实现一对一及一对多映射。association、collection 具备延迟加载功能。

Mybatis 缓存

Mybatis 中缓存分为一级缓存,二级缓存。
在这里插入图片描述

一级缓存

一级缓存是 SqlSession 级别的缓存,只有当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

例如:

第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。 得到用户信息,将用户信息存储到一级缓存中。

如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息

二级缓存

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

例如

sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

如果 SqlSession3 去执行相同 mapper 映射下 sql,执行 commit 提交,将会清空该 mapper 映射下的二 级缓存区域的数据。

sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从 缓存中取出数据

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章