面试题88:说一下MyBatis的一级缓存和二级缓存

2023-05-10 09:42:59 浏览数 (1)

【一级缓存】

  • MyBatis默认开启一级缓存,即:同一个SqlSession对象调用同一个Mapper的方法,如果没有声明需要刷新,并且缓存没超时的情况下,一般只执行一次SQL,其他的查询SqlSession都只会取出当前缓存的数据。如下所示:
  • CacheExecuter.java
代码语言:javascript复制
public class CacheExecuter {
    public static void main(String[] args) {
        SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user1 = userMapper.getUserById(1L);
        System.out.println("----真实查询-----user1 = "   user1);
        User user2 = userMapper.getUserById(1L);
        System.out.println("----缓存查询-----user2 = "   user2);

        /**
         * 开启了新的sqlSession,则无法利用一级缓存。因为一级缓存是sqlSession之间隔离的。
         */
        sqlSession = SqlSessionFactoryUtil.openSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        User user3 = userMapper.getUserById(1L);
        System.out.println("----真实查询-----user3 = "   user3);
    }
}

输出如下:

代码语言:javascript复制
Created connection 1071097621.
Returned connection 1071097621 to pool.
Cache Hit Ratio [mapper.UserMapper]: 0.0
Opening JDBC Connection
Checked out connection 1071097621 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3fd7a715]
==>  Preparing: select id, name, age from tb_user where id = ? 
==> Parameters: 1(Long)
<==    Columns: id, name, age
<==        Row: 1, muse1, 22
<==      Total: 1
----真实查询-----user1 = User{id=1, name='muse1', age=22, userContacts=null}
Cache Hit Ratio [mapper.UserMapper]: 0.0
----缓存查询-----user2 = User{id=1, name='muse1', age=22, userContacts=null}
Cache Hit Ratio [mapper.UserMapper]: 0.0
Opening JDBC Connection
Created connection 280265505.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@10b48321]
==>  Preparing: select id, name, age from tb_user where id = ? 
==> Parameters: 1(Long)
<==    Columns: id, name, age
<==        Row: 1, muse1, 22
<==      Total: 1
----真实查询-----user3 = User{id=1, name='muse1', age=22, userContacts=null}

Process finished with exit code 0

【二级缓存】

  • 在UserMapper.xml中添加<cache/>标签。
  • sqlSession.commit(); 当使用二级缓存的时候,只有调用了commit方法后才会生效。
  • POJO必须实现Serializable接口。

实现如下所示:

  • UserMapper.xml
代码语言:javascript复制
<cache/>
  • User.java
代码语言:javascript复制
public class User implements Serializable
  • CacheExecuter.java
代码语言:javascript复制
public class CacheExecuter {
    public static void main(String[] args) {
        SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user1 = userMapper.getUserById(1L);
        System.out.println("----真实查询-----user1 = "   user1);

        //当使用二级缓存的时候,只有调用了commit方法后才会生效。
        sqlSession.commit();

        User user2 = userMapper.getUserById(1L);
        System.out.println("----缓存查询-----user2 = "   user2);

        /**
         * 开启了新的sqlSession,则无法利用一级缓存。因为一级缓存是sqlSession之间隔离的。
         */
        sqlSession = SqlSessionFactoryUtil.openSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        User user3 = userMapper.getUserById(1L);
        System.out.println("----缓存查询-----user3 = "   user3);
    }
}

输入如下:

代码语言:javascript复制
Created connection 1071097621.
Returned connection 1071097621 to pool.
Cache Hit Ratio [mapper.UserMapper]: 0.0
Opening JDBC Connection
Checked out connection 1071097621 from pool.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3fd7a715]
==>  Preparing: select id, name, age from tb_user where id = ? 
==> Parameters: 1(Long)
<==    Columns: id, name, age
<==        Row: 1, muse1, 22
<==      Total: 1
----真实查询-----user1 = User{id=1, name='muse1', age=22, userContacts=null}
Cache Hit Ratio [mapper.UserMapper]: 0.5
----缓存查询-----user2 = User{id=1, name='muse1', age=22, userContacts=null}
Cache Hit Ratio [mapper.UserMapper]: 0.6666666666666666
----缓存查询-----user3 = User{id=1, name='muse1', age=22, userContacts=null}
  • 配置缓存参数UserMapper.xml
代码语言:javascript复制
<cache eviction="LRU" flushInterval="1000" size="1000" readOnly="true"/>

【参数解释】

eviction:缓存回收策略:

  • LRU:最近最少使用,移除最长时间不用的对象。
  • FIFO:先进先出,按对象进入缓存的顺序来移除它们。
  • SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK:弱引用,移除最长时间不用的对象。

flushInterval:刷新间隔时间,单位为毫秒。如果不配置,那么当SQL被执行的时候才会去刷新缓存。

size:引用数据,正整数,代表缓存最多可以存储多少个对象,不宜设置过大。否则会内存溢出。

readOnly:只读。

0 人点赞