MyBatis的缓存示例

1、一级缓存,即SqlSession范围的缓存(默认开启,不需要配置)。

 SqlSession工厂类代码如下:

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 FKSqlSessionFactory {
	
	private static SqlSessionFactory sqlSessionFactory = null;
	
	// 初始化创建SqlSessionFactory对象
	static{
		try {
			// 读取mybatis-config.xml文件
			InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder()
					.build(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 获取SqlSession对象的静态方法
	public static SqlSession getSqlSession(){
		return sqlSessionFactory.openSession();
	}

	// 获取SqlSessionFactory的静态方法
	public static SqlSessionFactory getSqlSessionFactory() {
		return sqlSessionFactory;
	}

}

测试代码及解释如下:

import org.apache.ibatis.session.SqlSession;
import org.fkit.domain.User;
import org.fkit.factory.FKSqlSessionFactory;
import org.fkit.mapper.UserMapper;

public class TestOneLevelCache {

	public static void main(String[] args) throws Exception {
		
		TestOneLevelCache t = new TestOneLevelCache();
		
		//t.testCache1();
	//t.testCache2();
		t.testCache3();
	}
	
	 /*
	  * 一级缓存: 也就Session级的缓存(默认开启)
	  */
	public void testCache1 (){
		// 使用工厂类获得SqlSession对象
		SqlSession session = FKSqlSessionFactory.getSqlSession();
		// 获得UserMapping对象
		UserMapper um = session.getMapper(UserMapper.class);
		// 查询id为1的User对象,会执行select语句
		User user = um.selectUserById(1);
		System.out.println(user);
		// 再次查询id为1的User对象,因为是同一个SqlSession,所以会从之前的一级缓存中查找数据
		User user2 = um.selectUserById(1);
		System.out.println(user2);
		// 关闭SqlSession对象
		session.close();
	}
	
	public void testCache2 (){
		// 使用工厂类获得SqlSession对象
		SqlSession session = FKSqlSessionFactory.getSqlSession();
		// 获得UserMapping对象
		UserMapper um = session.getMapper(UserMapper.class);
		// 查询id为1的User对象,会执行select语句
		User user = um.selectUserById(1);
		System.out.println(user);
		// 执行delete操作
		um.deleteUserById(2);
		// commit提交
		session.commit();
		// 再次查询id为1的User对象,因为DML操作会清空SqlSession缓存,所以会再次执行select语句
		User user2 = um.selectUserById(1);
		System.out.println(user2);
		// 关闭SqlSession对象
		session.close();
	}
	
	public void testCache3 (){
		// 使用工厂类获得SqlSession对象
		SqlSession session = FKSqlSessionFactory.getSqlSession();
		// 获得UserMapping对象
		UserMapper um = session.getMapper(UserMapper.class);
		// 查询id为1的User对象,会执行select语句
		User user = um.selectUserById(1);
		System.out.println(user);
		// 关闭一级缓存
		session.close();
		// 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
		session = FKSqlSessionFactory.getSqlSession();
		// 再次获得UserMapping对象
		um = session.getMapper(UserMapper.class);
		// 再次访问,因为现在使用的是一个新的SqlSession对象,所以会再次执行select语句
		User user2 = um.selectUserById(1);
		System.out.println(user2);
		// 关闭SqlSession对象
		session.close();
	}

}

testCache1方法运行结果如下:

DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, name=jack, sex=男, age=22]
User [id=1, name=jack, sex=男, age=22]

因为开启了一级缓存,所以相同的查询操作,不会发出sql语句去查询数据库,而从一级缓存中找。

testCache2方法运行结果如下:

DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, name=jack, sex=男, age=22]
DEBUG [main] - ==>  Preparing: DELETE FROM TB_USER WHERE id = ? 
DEBUG [main] - ==> Parameters: 2(Integer)
DEBUG [main] - <==    Updates: 0
DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, name=jack, sex=男, age=22]

因为中间执行了增删改操作,为了保证缓存中的数据是最新的,所以相同的查询操作会再次发出sql语句去查询数据库。

testCache3方法运行结果同上,因为close方法会清除一级缓存,所以需要重新获取SqlSession,因为是新的SqlSession,所以会发出sql。

2、二级缓存,即mapper级别的缓存(需要配置)

在配置文件的根元素<configuration>直接下级的<settings></settings>元素中开启二级缓存,代码如下:

<!-- 指定 MyBatis 所用日志的具体实现 -->
	<settings>
		<setting name="logImpl" value="LOG4J"/>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

测试代码及解释如下:

public void testCache2 (){
		// 使用工厂类获得SqlSession对象
		SqlSession session = FKSqlSessionFactory.getSqlSession();
		// 获得UserMapping对象
		UserMapper um = session.getMapper(UserMapper.class);
		// 查询id为1的User对象,会执行select语句
		User user = um.selectUserById(1);
		System.out.println(user);
		// 关闭一级缓存
		session.close();
		// 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
		session = FKSqlSessionFactory.getSqlSession();
		// 再次获得UserMapping对象
		um = session.getMapper(UserMapper.class);
		// 再次访问,因为现在使用的是一个新的SqlSession对象,所以会再次执行select语句
		//但因为开启了二级缓存,所以会去二级缓存中找,所以不会发送sql语句
		User user2 = um.selectUserById(1);
		System.out.println(user2);
		// 关闭SqlSession对象
		session.close();
	}

控制台输出结果如下:

DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.0
DEBUG [main] - ==>  Preparing: SELECT * FROM TB_USER WHERE id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User [id=1, name=jack, sex=男, age=22]
DEBUG [main] - Cache Hit Ratio [org.fkit.mapper.UserMapper]: 0.5
User [id=1, name=jack, sex=男, age=22]

在持久化类的mapper映射文件中的配置:

<!-- 开启二级缓存 
   	回收策略为先进先出
   	自动刷新时间60s
   	最多缓存512个引用对象
   	只读
   -->
	<cache 
	eviction="LRU"  
	flushInterval="60000" 
	size="512" 
	readOnly="true"/> 

另外,mapper文件中<select>元素中有个叫userCache的属性,值为true或false。默认为true,即允许查询语句使用二级缓存,false则相反。

总结:

一级缓存的范围为SqlSession,相同的SqlSession发出同一查询操作时,共享缓存数据;二级缓存的范围为mapper,是跨SqlSession的,不同的SqlSession操作mapper映射文件中的查询语句时(开启了二级缓存),可以共享缓存数据。一级缓存中找不到需要数据,则会去二级缓存中找,再找不到,则会发出sql语句去查数据库。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值