【第10章】Mybatis映射篇之缓存


前言

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。


一、缓存

1. 启用

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

基本上就是这样。这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

2. 属性

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT– 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
    默认的清除策略是 LRU。

flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

3. 单条语句应用

<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

4. 用例

缓存中要用到的Java Bean需要实现Serializable接口

1. 结果映射

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.example.mybatis.mapper.VehicleMapper">
    <cache/>
    <resultMap id="vehicleResult" type="Vehicle">
        <id property="id" column="id" />
        <result property="vin" column="vin"/>
        <result property="year" column="year"/>
        <result property="make" column="make"/>
        <result property="model" column="model"/>
        <result property="color" column="color"/>
        <discriminator javaType="int" column="vehicle_type">
            <case value="1" resultType="Car">
                <result property="tayCan" column="tay_can" />
            </case>
            <case value="2" resultType="Suv">
                <result property="haFo" column="ha_fo" />
            </case>
            <case value="3" resultType="Truck">
                <result property="piKa" column="pi_ka" />
            </case>
            <case value="4" resultType="Van">
                <result property="zhongQi" column="zhong_qi" />
            </case>
        </discriminator>
    </resultMap>

    <select id="selectList" resultMap="vehicleResult">
        select * from vehicle
    </select>
    <insert id="insert">
        insert into vehicle(id) value(#{id})
    </insert>

</mapper>

2 . 首次查询

RequestFilter-before
[2024-05-12 10:37:13.277][http-nio-8080-exec-1][DEBUG]- org.springframework.core.log.LogFormatUtils.traceDebug(LogFormatUtils.java:120) - GET "/mybatis/007", parameters={}
[2024-05-12 10:37:13.305][http-nio-8080-exec-1][DEBUG]- org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:531) - Mapped to org.example.mybatis.controller.MybatisController#mybatis007()
[2024-05-12 10:37:13.317][http-nio-8080-exec-1][DEBUG]- org.example.springmvc.params.controller.interceptor.LogInterceptor.preHandle(LogInterceptor.java:26) - preHandle:method[public void org.example.mybatis.controller.MybatisController.mybatis007()],parameters[[]]
[2024-05-12 10:37:13.392][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:60) - Cache Hit Ratio [org.example.mybatis.mapper.VehicleMapper]: 0.0
[2024-05-12 10:37:13.406][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:143) - Opening JDBC Connection
[2024-05-12 10:37:13.406][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:448) - Checked out connection 245679118 from pool.
[2024-05-12 10:37:13.406][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:107) - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@ea4c40e]
[2024-05-12 10:37:13.415][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==>  Preparing: select * from vehicle
[2024-05-12 10:37:13.473][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==> Parameters: 
[2024-05-12 10:37:13.540][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - <==      Total: 5
Car{tayCan='人车合一,我心澎湃'} Vehicle(id=1, vin=工业明珠, year=2024, make=made in china, model=自主, color=霞光紫, vehicleType=1)
Suv{haFo='哈弗H6'} Vehicle(id=2, vin=工业明珠, year=2024, make=made in china, model=自主, color=水晶白, vehicleType=2)
Truck{piKa='赛博皮卡'} Vehicle(id=3, vin=工业明珠, year=2024, make=made in china, model=合资, color=棕色灰, vehicleType=3)
Van{zhongQi='中国重汽'} Vehicle(id=4, vin=工业明珠, year=2024, make=made in china, model=自主, color=浅色绿, vehicleType=4)
Vehicle(id=5, vin=工业明珠, year=2024, make=made in china, model=自主, color=海湾蓝, vehicleType=5)
RequestFilter-after

3. 第二次查询

RequestFilter-before
[2024-05-12 10:37:24.873][http-nio-8080-exec-2][DEBUG]- org.springframework.core.log.LogFormatUtils.traceDebug(LogFormatUtils.java:120) - GET "/mybatis/007", parameters={}
[2024-05-12 10:37:24.873][http-nio-8080-exec-2][DEBUG]- org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:531) - Mapped to org.example.mybatis.controller.MybatisController#mybatis007()
[2024-05-12 10:37:24.874][http-nio-8080-exec-2][DEBUG]- org.example.springmvc.params.controller.interceptor.LogInterceptor.preHandle(LogInterceptor.java:26) - preHandle:method[public void org.example.mybatis.controller.MybatisController.mybatis007()],parameters[[]]
[2024-05-12 10:37:24.884][http-nio-8080-exec-2][WARN]- org.apache.ibatis.io.SerialFilterChecker.check(SerialFilterChecker.java:45) - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
[2024-05-12 10:37:24.886][http-nio-8080-exec-2][DEBUG]- org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:60) - Cache Hit Ratio [org.example.mybatis.mapper.VehicleMapper]: 0.5
Car{tayCan='人车合一,我心澎湃'} Vehicle(id=1, vin=工业明珠, year=2024, make=made in china, model=自主, color=霞光紫, vehicleType=1)
Suv{haFo='哈弗H6'} Vehicle(id=2, vin=工业明珠, year=2024, make=made in china, model=自主, color=水晶白, vehicleType=2)
Truck{piKa='赛博皮卡'} Vehicle(id=3, vin=工业明珠, year=2024, make=made in china, model=合资, color=棕色灰, vehicleType=3)
Van{zhongQi='中国重汽'} Vehicle(id=4, vin=工业明珠, year=2024, make=made in china, model=自主, color=浅色绿, vehicleType=4)
Vehicle(id=5, vin=工业明珠, year=2024, make=made in china, model=自主, color=海湾蓝, vehicleType=5)
RequestFilter-after

4.刷新缓存(执行插入)

RequestFilter-before
[2024-05-12 10:37:39.248][http-nio-8080-exec-9][DEBUG]- org.springframework.core.log.LogFormatUtils.traceDebug(LogFormatUtils.java:120) - POST "/mybatis/008", parameters={masked}
[2024-05-12 10:37:39.248][http-nio-8080-exec-9][DEBUG]- org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:531) - Mapped to org.example.mybatis.controller.MybatisController#mybatis008(int)
[2024-05-12 10:37:39.249][http-nio-8080-exec-9][DEBUG]- org.example.springmvc.params.controller.interceptor.LogInterceptor.preHandle(LogInterceptor.java:26) - preHandle:method[public void org.example.mybatis.controller.MybatisController.mybatis008(int)],parameters[[method 'mybatis008' parameter 0]]
[2024-05-12 10:37:39.302][http-nio-8080-exec-9][DEBUG]- org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:143) - Opening JDBC Connection
[2024-05-12 10:37:39.303][http-nio-8080-exec-9][DEBUG]- org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:448) - Checked out connection 245679118 from pool.
[2024-05-12 10:37:39.303][http-nio-8080-exec-9][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==>  Preparing: insert into vehicle(id) value(?)
[2024-05-12 10:37:39.304][http-nio-8080-exec-9][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==> Parameters: 6(Integer)
[2024-05-12 10:37:39.310][http-nio-8080-exec-9][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - <==    Updates: 1
1
RequestFilter-after

5. 再次查询

RequestFilter-before
[2024-05-12 10:38:05.006][http-nio-8080-exec-4][DEBUG]- org.springframework.core.log.LogFormatUtils.traceDebug(LogFormatUtils.java:120) - GET "/mybatis/007", parameters={}
[2024-05-12 10:38:05.007][http-nio-8080-exec-4][DEBUG]- org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:531) - Mapped to org.example.mybatis.controller.MybatisController#mybatis007()
[2024-05-12 10:38:05.007][http-nio-8080-exec-4][DEBUG]- org.example.springmvc.params.controller.interceptor.LogInterceptor.preHandle(LogInterceptor.java:26) - preHandle:method[public void org.example.mybatis.controller.MybatisController.mybatis007()],parameters[[]]
[2024-05-12 10:38:05.007][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.cache.decorators.LoggingCache.getObject(LoggingCache.java:60) - Cache Hit Ratio [org.example.mybatis.mapper.VehicleMapper]: 0.3333333333333333
[2024-05-12 10:38:05.008][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:143) - Opening JDBC Connection
[2024-05-12 10:38:05.008][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:448) - Checked out connection 245679118 from pool.
[2024-05-12 10:38:05.008][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(JdbcTransaction.java:107) - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@ea4c40e]
[2024-05-12 10:38:05.008][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==>  Preparing: select * from vehicle
[2024-05-12 10:38:05.009][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - ==> Parameters: 
[2024-05-12 10:38:05.011][http-nio-8080-exec-4][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - <==      Total: 6
Car{tayCan='人车合一,我心澎湃'} Vehicle(id=1, vin=工业明珠, year=2024, make=made in china, model=自主, color=霞光紫, vehicleType=1)
Suv{haFo='哈弗H6'} Vehicle(id=2, vin=工业明珠, year=2024, make=made in china, model=自主, color=水晶白, vehicleType=2)
Truck{piKa='赛博皮卡'} Vehicle(id=3, vin=工业明珠, year=2024, make=made in china, model=合资, color=棕色灰, vehicleType=3)
Van{zhongQi='中国重汽'} Vehicle(id=4, vin=工业明珠, year=2024, make=made in china, model=自主, color=浅色绿, vehicleType=4)
Vehicle(id=5, vin=工业明珠, year=2024, make=made in china, model=自主, color=海湾蓝, vehicleType=5)
Vehicle(id=6, vin=null, year=0, make=null, model=null, color=null, vehicleType=0)
RequestFilter-after

二、自定义缓存

1. 实现接口

public interface Cache {
  String getId();
  int getSize();
  void putObject(Object key, Object value);
  Object getObject(Object key);
  boolean hasKey(Object key);
  Object removeObject(Object key);
  void clear();
}

2.启用

<cache type="com.domain.something.MyCustomCache">
  <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
</cache>

3. 引用另一个缓存

<cache-ref namespace="com.someone.application.data.SomeMapper"/>

总结

回到顶部

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值