目录
一、缓存介绍
1、为什么使用缓存
2、Mybatis中的一级缓存和二级缓存
一级缓存
二级缓存
二、一级缓存
测试
总结
三、二级缓存
实现接口
开启二级缓存
在SqlMapConfig.xml 文件开启二级缓存
配置相关的Mapper映射文件
测试
总结
首次访问时,查询数据库,并将数据存储到内存中;再次访问时直接访问缓存,减少IO、硬盘读写次数、提高效率
它指的是mybatis中的SqlSession对象的缓存。当我们执行完查询之后,查询的结果会同时存在在SqlSession为我们提供的一块区域中。当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来使用。当SqlSession对象消失时,Mybatis的一级缓存也就消失了。
它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessioFactory对象创建的SqlSession共享其缓存。
UserMapper
接口
public interface UserMapper {
User getUserById(Integer id);
void deleteUserById(Integer id);
}
UserMapper
XML 映射文件
delete from user where id=#{id}
测试类
public class MyBatisFirstCacheTest {
private SqlSession sqlSession;
private InputStream inputStream;
private SqlSessionFactory sessionFactory;
@Before
public void init() throws IOException {
//加载mybatis-config.xml
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
//创建sqlSessionFactory
sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建sqlSession
sqlSession = sessionFactory.openSession();
}
@Test
public void testGoCache(){
SqlSession sqlSession = sessionFactory.openSession();
//拥有同一个sqlsession
UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行查询
System.out.println(user1);
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行查询?
System.out.println(user2);
}
@Test
public void testNoGoCache(){
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//拥有不同的sqlsession
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行查询
System.out.println(user1);
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行查询?不执行
System.out.println(user2);
}
@Test
public void testNoGoCache2(){
SqlSession sqlSession = sessionFactory.openSession();
//拥有同一个sqlsession
UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行查询
System.out.println(user1);
System.out.println("=============两次查询之间执行增删改=============");
userMapper1.deleteUserById(1);
sqlSession.commit();
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行查询
System.out.println(user2);
}
@After
public void close() throws IOException {
/* sqlSession.close();
inputStream.close();*/
}
}
testGoCache()
Debug运行,可以看到是同一个sqlSession testNoGoCache()
testNoGoCache2()
一级缓存范围是sqlSession,即在同一个会话的sqlSession中执行查询语句,查询结果已经被缓存,再次查询该语句时,不需要在执行查询语句,直接从缓存中读取即可
一级缓存是默认开启的
当使用不同sqlSession 或 两次查询之间执行了增删改操作时(MyBatis 会默认清空该会话的一级缓存,以确保缓存中的数据与数据库的状态保持一致,避免脏读),一级缓存就失效了,每次操作都需要执行查询语句
注意:当我们在使用二级缓存时,所缓存的类一定要实现java.io.Serializable接口,这种就可以使用序列化方式来保存对象。
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private Date birthday;
private String sex;
private String address;
//set get... ...
}
UserMapper
接口
public interface UserMapper {
User getUserById(Integer id);
void deleteUserById(Integer id);
}
UserMapper
XML 映射文件
delete from user where id=#{id}
测试类
public class MyBatisSecondCacheTest {
private SqlSession sqlSession;
private InputStream inputStream;
private SqlSessionFactory sessionFactory;
@Before
public void init() throws IOException {
//加载mybatis-config.xml
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
//创建sqlSessionFactory
sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建sqlSession
sqlSession = sessionFactory.openSession();
}
@Test
public void testGoCache(){
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//拥有相同的sqlSessionFactrory
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行sql
System.out.println(user1);
sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行sql?不执行sql
System.out.println(user2);
}
@Test
public void testNoGoCache() throws IOException {
//加载mybatis-config.xml
String resource = "mybatis-config.xml";
InputStream inputStream1 = Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(inputStream1);
InputStream inputStream2 = Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory2 = new SqlSessionFactoryBuilder().build(inputStream2);
SqlSession sqlSession1 = sessionFactory1.openSession();
SqlSession sqlSession2 = sessionFactory2.openSession();
//拥有不相同的sqlSessionFactrory
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行sql
System.out.println(user1);
sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行sql?执行sql
System.out.println(user2);
}
@Test
public void testNoGoCache2(){
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//拥有相同的sqlSessionFactrory
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println("=============第一次查询============");
User user1 = userMapper1.getUserById(41); //执行sql
System.out.println(user1);
sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存
System.out.println("=============两次查询之间执行增删改查=============");
userMapper1.deleteUserById(1);
sqlSession1.commit();
System.out.println("=============第二次查询============");
User user2 = userMapper2.getUserById(41);//执行sql?执行sql
System.out.println(user2);
}
@After
public void close() throws IOException {
/* sqlSession.close();
inputStream.close();*/
}
}
testGoCache()
testNoGoCache()
testNoGoCache2()
二级缓存范围是sqlSessionFactory,即当开启二级缓存后,在一个应用中的不同 SqlSession
中执行相同的查询可以共享二级缓存,避免重复访问数据库。
二级缓存需要手动开启
当使用不同sqlSessionFactory 或 两次查询之间执行了增删改操作时(MyBatis 在默认情况下会在执行增删改操作时,清空对应的 SqlSessionFactory
的二级缓存。这是为了确保数据的一致性,避免脏读等问题),二级缓存就失效了,每次操作都需要执行查询语句。