mybatis的缓存

1、一级缓存

  一级缓存默认开启,缓存的生命周期与sqlSession相同,当对数据库执行插入 更新 删除操作后缓存失效。

       SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        UserMapper userMapper = session.getMapper(UserMapper.class);

        User user = userMapper.getUserById(1);
        System.out.println(user);
        user.setUserName("yyy");
        User user2 = userMapper.getUserById(1);
        System.out.println(user2);
        System.out.println(user==user2);

  在同一个sqlSession里先查询出id为1的user,然后修改该user的Name属性,再没有提交事务的情况下再次用相同的查询方法传入相同的参数去查询,发现查询出来的use2r完成修改,好像修改Name属性的事务已经提交,且user和user2是同一个对象。观察控制台日志发现只有查询user的时候和数据库产生了交互,第二次查询user2的时候并没和数据库产生交互。

  mybatis的一级缓存是一个map,map的key是查询语句和参数,value是查询出的对象,当修改查询出来的对象的时候会在没有提交事务的前提下修改缓存里的对象,这样在第二次用同样的查询语句和参数进行查询的时候能够查询出之前对对象的修改,即使这个修改并没有提交给数据库。

 

  任何对数据库修改的语句都会使该sqlsession对应的缓存失效。在两次查询之间插入一条删除语句,控制台输出日志可以发现两次查询都与数据库产生了交互,且user2和user不是用同一个对象,对user的修改对user2并没有生效。

        User user = userMapper.getUserById(1);
        System.out.println(user);
        user.setUserName("yyy");
        userMapper.deleteById(3);
        User user2 = userMapper.getUserById(1);
        System.out.println(user2);
        System.out.println(user==user2);
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
User{id=1, userName='xxx', passWord='', email='qq.com'}
==>  Preparing: delete from user where id = 3 
==> Parameters: 
<==    Updates: 1
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
User{id=1, userName='xxx', passWord='', email='qq.com'}
false

  

  sqlSession的缓存是以sqlsession为单位,不同的sqlsession缓存彼此独立。开启两个sqlSession,在其中一个session中对查询出的对象修改再另一个session中并体现不出来,且执行了两次数据库查询也可以体现出第二次查询的时候缓存未命中。

 User user = userMapper.getUserById(1);
        System.out.println(user);
        user.setUserName("yyy");


        System.out.println("开启新的缓存");
        SqlSession session2 = factory.openSession();
        UserMapper mapper2 = session2.getMapper(UserMapper.class);
        User user3 = mapper2.getUserById(1);
        System.out.println(user3);
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@131276c2]
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
User{id=1, userName='xxx', passWord='', email='qq.com'}
开启新的缓存
Opening JDBC Connection
Tue Mar 26 12:31:14 CST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Created connection 811587677.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@305fd85d]
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
User{id=1, userName='xxx', passWord='', email='qq.com'}

  

  那那么在session1中修改了查询出的对象,会使session2中的缓存失效吗?在session1执行删除操作之前,session2查询出的user2和user2_2指向同一个对象,而在session1删除之后user2 和user2_3不再指向同一个对象。

        SqlSession session1 = factory.openSession();
        UserMapper mappe1 = session1.getMapper(UserMapper.class);
        SqlSession session2 = factory.openSession();
        UserMapper mapper2 = session2.getMapper(UserMapper.class);

        User user2 = mapper2.getUserById(1);
        User user2_2 = mapper2.getUserById(1);
        User user1 = mappe1.getUserById(1);
        System.out.println(user2==user2_2);
        mapper2.deleteById(2);
        User user2_3 = mapper2.getUserById(1);
        System.out.println(user2 == user2_3);

  总结:

  • 观察查询是通过缓存还是通过数据库查询可以观察日志
  • 一级缓存是为了提高查询效率,为session私有,其生命周期与session相同,当出现对数据库修改的操作后一级缓存失效
  • 默认开启,可在mapper文件中关闭

 

2、二级缓存

2.1 二级缓存的开启

  二级缓存并非默认开启,需要在两个地方开启:1、全局mybatis,在setting中开启,默认开启无需配置 2、mapper中,<cache/>开启该mapper的二级缓存,cache标签也有许多配置可供配置对应着cache的不同特点。

  

2.2 二级缓存的使用

  二级缓存是sqlSessionFactory层面上的缓存,要求被缓存的对象实现了Serializable接口,即缓存的实现是把被缓存的对象存储在磁盘上。

  在session中查询user并关闭session,在session2中查询同一个对象的时候从控制台的输出可以发现并没有执行数据库的操作。虽然没有执行数据库查询但是user和user2仍然不是同一个对象因为对象的序列化和反序列化前后得到的并不是同一个对象。

        SqlSession session1 = factory.openSession();
        UserMapper mappe1 = session1.getMapper(UserMapper.class);
        SqlSession session2 = factory.openSession();
        UserMapper mapper2 = session2.getMapper(UserMapper.class);

        User user1 = mappe1.getUserById(1);
        session1.close();

        User user2 = mapper2.getUserById(1);
        System.out.println(user2==user1);
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@394e1a0f]
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@394e1a0f]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@394e1a0f]
Returned connection 961419791 to pool.
Cache Hit Ratio [mapper.UserMapper]: 0.5
false

 

2.3 二级缓存的读写配置

  cache标签中的readonly默认是可读写,如果把缓存设置成只读,那么对象在写入缓存之后就不会被修改,在一定程度上可以提供线程安全,此时二级缓存的实现和一级缓存相同都是使用map实现,此时的pojo类可以不必实现Serializable接口,并且缓存命中后读取出的对象是同一个对象。

  

 SqlSession session1 = factory.openSession();
        UserMapper mappe1 = session1.getMapper(UserMapper.class);
        SqlSession session2 = factory.openSession();
        UserMapper mapper2 = session2.getMapper(UserMapper.class);

        User user1 = mappe1.getUserById(1);
        session1.close();

        User user2 = mapper2.getUserById(1);
        System.out.println(user2==user1);
Created connection 1454031203.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@56aac163]
==>  Preparing: select * from user where id = ? 
==> Parameters: 1(Integer)
<==    Columns: id, user_name, email, password
<==        Row: 1, xxx, qq.com, 
<==      Total: 1
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@56aac163]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@56aac163]
Returned connection 1454031203 to pool.
Cache Hit Ratio [mapper.UserMapper]: 0.5
true

 

  

  

posted @ 2019-03-26 13:27  AshOfTime  阅读(221)  评论(0编辑  收藏  举报