您的位置:首页 > 其它

mybatis缓存-一级缓存

2022-03-25 16:14 621 查看

1.缓存

  • 【官方声明】

    MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

  • 一级缓存(SqlSession级别)

  • 二级缓存(mapper||namespace级别)

1.1 一级缓存

1.1.1 什么是一级缓存?

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。

1.1.2 一级缓存的作用

在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

1.1.3 一级缓存的生命周期有多长?

  1. MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
  2. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。
  3. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。
  4. SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

1.1.4 如何判断缓存目标?

  1. 传入的statementId
  2. 查询时要求的结果集中的结果范围
  3. 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )
  4. 传递给java.sql.Statement要设置的参数值

1.1.5 测试

  1. Dao层接口添加测试方法 => 【UserMapper】
public interface UserMapper {
//根据Id查询用户
User queryUserById(@Param("id") int id);

//更新用户
int updateUser(User user);
}
  1. 核心XML配置文件 => 【mybatis-config.xml】
<settings>
...
<!-- 	全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。
默认状态: 开启 => value="true"  -->
<!-- 显示开启一级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
  1. XML映射文件 => 【UserMapper.xml】
<mapper namespace="com.zhang.dao.UserMapper">
<select id="queryUserById" resultType="user">
select * from mybatis.user where id=#{id}
</select>

<update id="updateUser" parameterType="user">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
</mapper>
  1. 测试实现类

    [ol] 正常操作
[/ol]
@Test
public void Test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user01 = mapper.queryUserById(2);
System.out.println(user01.toString());
System.out.println("------------***************----------------");
User user02 = mapper.queryUserById(2);
System.out.println(user02.toString());
System.out.println(user01==user02);
sqlSession.close();
}

@Test
public void Test02(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user01 = mapper.queryUserById(2);
System.out.println(user01.toString());
User user = new User();
user.setId(3);
user.setPwd("6113081");
user.setName("FT");
int i = mapper.updateUser(user);
if (i >= 0) {
System.out.println("更新成功");
sqlSession.commit();
}else{
System.out.println("更新失败");
sqlSession.close();
}
System.out.println("------------***************----------------");
User user02 = mapper.queryUserById(2);
System.out.println(user02.toString());
System.out.println(user01==user02);
sqlSession.close();
}
  1. 日志输出
  • 1、 运行方法Test01结果(可以看出两次查询在一个sqlsession作用域内只调用了一次查询SQL语句,且结果为同一个User对象),而Test02方法在两次查询中插入了一个修改方法导致第二次调用同一查询方法时,第一次的查询缓存被清空,且两次查询的返回结果的对象不是同一个
  • 2、上述是一种自动清理mybatis缓存的实现,也可以手动清理只需在查询完成后添加sqlSession.clearCache()方法即可。
Test01输出日志
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1125381564.
==>  Preparing: select * from mybatis.user where id=?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, lisi, 123456
<==      Total: 1
User(id=2, name=lisi, pwd=123456)
------------***************----------------
User(id=2, name=lisi, pwd=123456)
true
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4313f5bc]
Returned connection 1125381564 to pool.

进程已结束,退出代码0
Test02输出日志
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1125381564.
==>  Preparing: select * from mybatis.user where id=?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, lisi, 123456
<==      Total: 1
User(id=2, name=lisi, pwd=123456)
==>  Preparing: update mybatis.user set name=?,pwd=? where id=?
==> Parameters: FT(String), 6113081(String), 3(Integer)
<==    Updates: 1
更新成功
------------***************----------------
==>  Preparing: select * from mybatis.user where id=?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, lisi, 123456
<==      Total: 1
User(id=2, name=lisi, pwd=123456)
false
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4313f5bc]
Returned connection 1125381564 to pool.

进程已结束,退出代码0

1.1.6 小结

MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的。即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,以后直接先从缓存中取出数据,不会直接去查数据库。

但是不同的SqlSession对象,因为不同的SqlSession都是相互隔离的,所以相同的Mapper、参数和方法,他还是会再次发送到SQL到数据库去执行,返回结果。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: