AI辅助论文写作实操指南:9个工具按流程选,别再用一键生成
2026/10/10 6:42:38
什么是缓存?
一级缓存核心定位
SqlSession(数据库会话)HashMap存储),缓存键由Mapper ID + SQL 语句 + 参数 + 分页信息 + 环境信息组成。核心价值:
减少同一 SqlSession 内重复查询的数据库交互,提升查询性能。
一级缓存生效与失效条件
| 场景类型 | 生效条件 | 失效条件 |
|---|---|---|
| 核心前提 | 同一 SqlSession、相同 Mapper ID+SQL + 参数 | 不同 SqlSession、SQL / 参数 / 分页不同 |
| 数据库操作影响 | 未执行增删改(insert/update/delete)操作 | 执行增删改操作(自动清空当前 SqlSession 缓存) |
| 手动干预 | 未调用clearCache()或close()方法 | 调用sqlSession.clearCache()(手动清空)、sqlSession.close()(关闭会话) |
| 配置影响 | 默认配置(无特殊禁用) | 全局配置localCacheScope=STATEMENT(禁用一级缓存) |
一级缓存工作流程
一级缓存核心特性:
@Service@Slf4jpublicclassUserService{@AutowiredprivateSqlSessionTemplatesqlSessionTemplate;/*一级缓存 有效的访问*/publicvoidfirstCache(){SqlSessionFactorysqlSessionFactory=sqlSessionTemplate.getSqlSessionFactory();SqlSessionsqlSession=sqlSessionFactory.openSession();UserMapperuserMapper=sqlSession.getMapper(UserMapper.class);Useruser=userMapper.selectById(1);log.info("第一次查询结果:{}",user);Useruser2=userMapper.selectById(1);log.info("第二次查询结果:{}",user2);log.info("两个user是否是同一个对象:{}",user==user2);sqlSession.close();}/*一级缓存 失效的访问*/publicvoidfirstCacheInvalidation(){SqlSessionFactorysqlSessionFactory=sqlSessionTemplate.getSqlSessionFactory();SqlSessionsqlSession=sqlSessionFactory.openSession();UserMapperuserMapper=sqlSession.getMapper(UserMapper.class);Useruser=userMapper.selectById(1);log.info("第一次查询结果:{}",user);/*执行 写的操作*/user.setAge(18);introws=userMapper.update(user);log.info("执行写的操作,影响行数:{}",rows);//清空缓存// sqlSession.clearCache();Useruser2=userMapper.selectById(1);log.info("第二次查询结果:{}",user2);log.info("两个user是否是同一个对象:{}",user==user2);sqlSession.close();}}核心概念界定
二级缓存核心定位
Serializable接口,需手动开启一级缓存与二级缓存核心区别
| 对比维度 | 一级缓存(SqlSession 级) | 二级缓存(Mapper 级) |
|---|---|---|
| 作用域 | 单个 SqlSession | 同一个 Mapper(namespace) |
| 共享性 | 不可跨 SqlSession 共享 | 可跨 SqlSession 共享 |
| 开启方式 | 默认开启,无需配置 | 需全局配置 + Mapper 配置手动开启 |
| 实体类要求 | 无强制序列化要求 | 必须实现 Serializable 接口 |
| 失效触发 | 同一 SqlSession 内增删改、clearCache () | 对应 Mapper 内增删改操作、缓存过期等 |
| 适用场景 | 单会话内重复查询 | 多会话共享高频查询数据 |
二级缓存工作流程
二级缓存开启条件(三步缺一不可)
cacheEnabled=true<cache/>标签java.io.Serializable接口(避免序列化异常)。二级缓存配置详解
mybatis:configuration:cache-enabled:true# 启用二级缓存<!-- Mapper XML 中配置二级缓存 --><mappernamespace="com.example.mapper.UserMapper"><!-- 开启二级缓存配置 --><cacheeviction="LRU"flushInterval="60000"size="512"readOnly="true"/><selectid="selectUserById"parameterType="long"resultType="User"useCache="true">SELECT * FROM user WHERE id = #{id}</select></mapper>二级缓存属性详解表
| 属性 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
eviction | LRU/FIFO/SOFT/WEAK | LRU | 缓存回收策略 |
flushInterval | 毫秒数 | 无 | 缓存刷新间隔 |
size | 正整数 | 1024 | 缓存引用数量 |
readOnly | true/false | false | 是否只读 |
blocking | true/false | false | 是否使用阻塞缓存 |
常见的缓存回收策略:
| 策略缩写 | 全称 | 策略说明 |
|---|---|---|
| LRU | Least Recently Used | 移除最长时间未被使用的对象(默认策略)。 |
| FIFO | First In First Out | 按对象进入缓存的顺序来移除它们。 |
| SOFT | Soft Reference | 基于垃圾回收器状态和软引用规则来移除对象。 |
| WEAK | Weak Reference | 更积极地基于垃圾收集器状态和弱引用规则移除对象。 |
// 使用二级缓存需要实体类实现Serializable接口@Data@NoArgsConstructor@AllArgsConstructorpublicclassUserimplementsSerializable{privateLongid;privateStringusername;privateStringemail;privateIntegerage;privateDatecreateTime;privateDateupdateTime;// 关联对象也需要序列化}// 二级缓存服务演示@Service@Slf4jpublicclassSecondLevelCacheService{@AutowiredprivateUserMapperuserMapper;/** * 演示二级缓存跨SqlSession共享 */publicvoiddemonstrateSecondLevelCache(){Useruser1=userMapper.selectUserById(1L);log.info("SqlSession查询: {}",user1);// 重新调用方法模拟第二个SqlSession(实际应用中可能是另一个请求)log.info("=== 二级缓存演示结束 ===");}/** * 二级缓存失效场景 */publicvoiddemonstrateSecondLevelCacheInvalidation(){// 执行更新操作Useruser1=newUser();user1.setId(1L);user1.setEmail("newemail@example.com");intupdateCount=userMapper.updateUser(user1);log.info("更新影响行数: {}",updateCount);}}懒加载核心定位
懒加载与立即加载对比
懒加载开启条件
lazyLoadingEnabled=true(默认 false)aggressiveLazyLoading=falseassociation或collection标签添加fetchType="lazy"(优先级高于全局配置)懒加载配置详解
mybatis:configuration:lazy-loading-enabled:true# 开启全局懒加载aggressive-lazy-loading:false# 关闭积极加载(按需加载)map-underscore-to-camel-case:true懒加载实战案例
<!-- 基础用户结果映射(不包含关联对象) --><resultMapid="BaseUserMap"type="com.example.entity.User"><idcolumn="user_id"property="userId"/><resultcolumn="user_name"property="userName"/><resultcolumn="card_id"property="cardId"/></resultMap><!-- 嵌套查询结果映射:使用子查询方式加载关联对象 --><resultMapid="UserWithIdCardNestedQueryMap"type="com.example.entity.User"extends="BaseUserMap"><associationproperty="idCard"column="card_id"select="com.example.mapper.IdCardMapper.selectById"javaType="com.example.entity.IdCard"fetchType="lazy"/></resultMap><!-- 嵌套查询方式:查询用户(触发子查询加载身份证) --><selectid="selectUserWithIdCardNested"resultMap="UserWithIdCardNestedQueryMap">SELECT user_id, user_name, card_id FROM t_user WHERE user_id = #{userId}</select>懒加载最佳实践
适用场景:
注意事项:
) -->
SELECT
user_id,
user_name,
card_id
FROM t_user
WHERE user_id = #{userId}
懒加载最佳实践 - 适用场景: - 关联数据量大,且不经常使用 - 需要快速响应的列表查询 - 移动端应用,减少数据传输 - 注意事项: - 注意 N+1 查询问题