文章目录
前言
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"/>