MyBatis 缓存机制

     在实际项目开发中,通常对数据库查询的性能要求很高,而MyBatis提供了查询缓存来缓存数据,从而达到提高查询性能的要求。MyBatis的查询缓存分为一级缓存(sqlSession级别)和二级缓存(mapper级别)。

一级缓存(sqlSession级别)

       一级缓存的作用域是sqlSession范围的,当在同一个sqlSession中执行两次相同的SQL语句时,第一次执行完毕会将从数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。需要注意的是,如果sqlSession执行了DML操作(insert、update、delete),并提交到数据库,MyBatis则会清空sqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。

      当一个sqlSession结束后该sqlSession的一级缓存也就不在了。MyBatis默认开启一级缓存,不需要进行任何配置。

示例:测试MyBatis缓存

程序清单:UserMapper.java

package com.mapper;
import com.po.User;
public interface UserMapper {
	//增加用户
	void addUser(User user);	
	//删除用户
	void deleteUser(Integer id);
	//根据id查询用户
	User getUserById(Integer id);
	//更新用户
	void updateUser(User user);
}

程序清单:UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.UserMapper">
	<!-- 删除用户 -->
	<delete id="deleteUser" parameterType="Integer">
		delete from t_user where id=#{id}
	</delete>
	<!-- 根据id查询用户 -->
	<select id="getUserById" parameterType="Integer" resultType="user" >
		select * from t_user where id=#{id}
	</select>
</mapper>

程序清单:UserDao.java

@Test
	public void getUserById() throws IOException {
		session=getSqlSession();
		UserMapper um=session.getMapper(UserMapper.class);
		User user=um.getUserById(2);
		User user1=um.getUserById(2);
		System.out.println(user);
		System.out.println(user1);
		session.close();
	}

运行UserDao类的getUserById() 方法,控制台显示如下:

     仔细观察MyBatis的执行结果,在第一次查询id为2的User对象时执行了一条select语句,但是第二次获取id为2的User对象时并没有执行select语句。因为此时一级缓存已经缓存了id为2的User对象,MyBatis直接从缓存中将对象取出来,并没有再次去数据库查询,所以第二次没有执行select语句。

程序清单:UserDao.java

@Test
	public void test() throws IOException {
		session=getSqlSession();
		UserMapper um=session.getMapper(UserMapper.class);
		User user=um.getUserById(2);
		System.out.println(user);
		um.deleteUser(3);
		session.commit();
		User user1=um.getUserById(2);
		System.out.println(user1);
	}

执行UserDao的test()方法,控制台显示如下:

    仔细观察MyBatis的执行结果,在第一次查询id为2的User对象时执行了一条select语句,接下来执行了一个delete操作,MyBatis为了保证缓存中存储的是最新信息,会清空SqlSession缓存。当第二次获取id为2的User对象时一级缓存并没有缓存任何对象,所以MyBatis再次执行select语句去查询id为2的User对象。

程序清单:UserDao.java

@Test
	public void test() throws IOException {
		session=getSqlSession();
		UserMapper um=session.getMapper(UserMapper.class);
		User user=um.getUserById(2);
		System.out.println(user);
		//清空一级缓存
		session.clearCache();
		um=session.getMapper(UserMapper.class);
		User user1=um.getUserById(2);
		System.out.println(user1);
	}

执行UserDao的test()方法,控制台显示如下:

    仔细观察MyBatis的执行结果,在第一次查询id为2的User对象时执行了一条select语句,接下来调用SqlSession的clearCache()方法,该方法会清空SqlSession缓存。第二次获取id为2的User对象时,MyBatis会再次执行select语句。

程序清单:UserDao.java

@Test
	public void test() throws IOException {
		session=getSqlSession();
		UserMapper um=session.getMapper(UserMapper.class);
		User user=um.getUserById(2);
		System.out.println(user);
		//关闭SqlSession连接
		session.close();
		//重新获取SqlSession
		SqlSession session2=getSqlSession();
		um=session2.getMapper(UserMapper.class);
		User user1=um.getUserById(2);
		System.out.println(user1);
	}

    仔细观察MyBatis的执行结果,在第一次查询id为2的User对象时执行了一条select语句,接下来调用SqlSession的close()方法,该方法会关闭SqlSession缓存。第二次获取id为2的User对象时,MyBatis会再次执行select语句。

二级缓存(mapper级别)

     使用二级缓存时,多个Sqlsession使用同一个mapper的SQL语句去操作数据库,得到的数据会存在二级缓存区域,多个SqlSession可以共享二级缓存中的数据。

示例:测试MyBatis二级缓存

在mybatis-config.xml开启二级缓存

<settings>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
</settings>

配置UserMapper.xml

<!-- 开启当前mapper的namespace下的二级缓存 -->
<cache eviction="LRU"  flushInterval="60000" size="512" readOnly="true"/>

程序清单:MySqlSessionFactory.java

package com.factory;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MySqlSessionFactory {
	private static SqlSessionFactory sqlSessionFactory=null;
	static {	
		try {
			InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
			sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static SqlSession getSqlSession(){
		return sqlSessionFactory.openSession();
	}
	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}
}

程序清单:UserDao.java

@Test
	public void test() throws IOException {
		session=MySqlSessionFactory.getSqlSession();
		UserMapper um=session.getMapper(UserMapper.class);
		User user=um.getUserById(2);
		System.out.println(user);
		//关闭SqlSession连接
		session.close();
		//重新获取SqlSession
		SqlSession session2=MySqlSessionFactory.getSqlSession();
		um=session2.getMapper(UserMapper.class);
		User user1=um.getUserById(2);
		System.out.println(user1);
		session2.close();
	}

执行UserDao的test()方法,控制台显示如下:

    仔细观察MyBatis的执行结果,日志中有几条以Cache Hit Ratio开头的语句,这行日志后面输出的值为当前执行方法的缓冲命中率。在第一次查询id为2的User对象时执行了一条select语句,接下来调用SqlSession的close()方法,该方法会关闭SqlSession一级缓存,同时会将查询数据保存到二级缓存中。当第二次获取id为2的User对象时,MyBatis会去二级缓存中查找,所以不会再次执行select语句。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云淡风轻58

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值