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级别的缓存(需要配置)

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


	
		
		
		
	

测试代码及解释如下:

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映射文件中的配置:


	 

另外,mapper文件中