怎么使用注解开启二级缓存,注解应该放在那里?

简介: 在 MyBatis 中,使用 `@CacheNamespace` 注解可开启二级缓存,该注解应添加在 Mapper 接口上。通过配置 `eviction`、`flushInterval`、`size` 等参数,可以控制缓存行为。此外,实体类需实现 `Serializable` 接口以确保缓存正常工作。

 提问:怎么使用注解开启二级缓存,注解应该放在那里?

在 MyBatis 中使用注解开启二级缓存,需要在 Mapper 接口上添加 @CacheNamespace 注解。让我详细解释:

  1. 基本用法: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace  // 开启二级缓存
    public interface UserMapper {
       // Mapper 方法
    }
  1. 完整示例: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace(
       eviction = LruCache.class,           // 缓存淘汰策略
       flushInterval = 60000,               // 刷新间隔(毫秒)
       size = 1024,                         // 缓存大小
       readWrite = true,                    // 是否读写
       blocking = false                     // 是否阻塞
    )
    public interface UserMapper {
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);
       
       @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
       int insertUser(User user);
    }
  1. 实体类配置: java
    Apply to TestJwt.java
    // 实体类需要实现 Serializable 接口
    public class User implements Serializable {
       private Integer id;
       private String name;
       private Integer age;
       
       // getter 和 setter
    }
  1. 缓存配置选项: java
    Apply to TestJwt.java
    @CacheNamespace(
       // 缓存实现类
       implementation = PerpetualCache.class,
       
       // 缓存淘汰策略
       eviction = LruCache.class,
       
       // 刷新间隔(毫秒)
       flushInterval = 60000,
       
       // 缓存大小
       size = 1024,
       
       // 是否读写
       readWrite = true,
       
       // 是否阻塞
       blocking = false
    )
  1. 缓存注解使用场景: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace
    public interface UserMapper {
       // 查询方法会被缓存
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);
       
       // 更新方法会清除缓存
       @Update("UPDATE user SET name = #{name} WHERE id = #{id}")
       int updateUser(User user);
       
       // 删除方法会清除缓存
       @Delete("DELETE FROM user WHERE id = #{id}")
       int deleteUser(Integer id);
    }
  1. 缓存控制: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace
    public interface UserMapper {
       // 使用 @Options 控制单个方法的缓存行为
       @Select("SELECT * FROM user WHERE id = #{id}")
       @Options(useCache = true)  // 使用缓存
       User getUserById(Integer id);
       
       // 禁用缓存
       @Select("SELECT * FROM user WHERE id = #{id}")
       @Options(useCache = false)  // 不使用缓存
       User getUserByIdNoCache(Integer id);
    }
  1. 最佳实践: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace(
       eviction = LruCache.class,
       flushInterval = 60000,
       size = 1024,
       readWrite = true
    )
    public interface UserMapper {
       // 查询方法
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);
       
       // 更新方法
       @Update("UPDATE user SET name = #{name} WHERE id = #{id}")
       int updateUser(User user);
       
       // 删除方法
       @Delete("DELETE FROM user WHERE id = #{id}")
       int deleteUser(Integer id);
    }
  1. 注意事项:
  • 实体类必须实现 Serializable 接口
  • 缓存会占用内存,注意设置合适的缓存大小
  • 更新操作会自动清除缓存
  • 注意缓存一致性问题
  1. 常见问题: java
    Apply to TestJwt.java
    // 错误:实体类没有实现 Serializable
    public class User {  // 错误
       private Integer id;
       private String name;
    }
    // 正确:实体类实现 Serializable
    public class User implements Serializable {  // 正确
       private Integer id;
       private String name;
    }
  1. 缓存配置建议:
  • 对于频繁查询但不常更新的数据,可以开启缓存
  • 对于实时性要求高的数据,可以禁用缓存
  • 根据数据量大小设置合适的缓存大小
  • 根据业务需求设置合适的刷新间隔

总结:

  • 在 Mapper 接口上使用 @CacheNamespace 注解开启二级缓存
  • 实体类必须实现 Serializable 接口
  • 可以通过注解参数配置缓存行为
  • 注意缓存一致性和性能问题
  • 根据业务需求选择合适的缓存配置

开启二级缓存的时候,实体类必须实现Serializable吗?

是的,在 MyBatis 中开启二级缓存时,实体类必须实现 Serializable 接口。这是因为:

  1. 为什么需要实现 Serializable:
  • 二级缓存会将对象序列化后存储
  • 序列化是对象持久化的过程
  • 反序列化是对象恢复的过程
  • 没有实现 Serializable 会导致序列化失败
  1. 正确的实体类定义: java
    Apply to TestJwt.java
    // 正确:实现 Serializable 接口
    public class User implements Serializable {
       private Integer id;
       private String name;
       private Integer age;
       
       // getter 和 setter
    }
    // 错误:没有实现 Serializable 接口
    public class User {  // 会导致序列化异常
       private Integer id;
       private String name;
       private Integer age;
    }
  1. 序列化版本号: java
    Apply to TestJwt.java
    public class User implements Serializable {
       // 建议添加序列化版本号
       private static final long serialVersionUID = 1L;
       
       private Integer id;
       private String name;
       private Integer age;
    }
  1. 常见错误: java
    Apply to TestJwt.java
    // 错误:没有实现 Serializable
    @Mapper
    @CacheNamespace
    public interface UserMapper {
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);  // 会抛出序列化异常
    }
    // 正确:实现 Serializable
    @Mapper
    @CacheNamespace
    public interface UserMapper {
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);  // 正常工作
    }
  1. 注意事项:
  • 所有被缓存的实体类都必须实现 Serializable
  • 实体类中的其他对象属性也需要实现 Serializable
  • 建议添加序列化版本号
  • 注意序列化性能影响

总结:

  • 开启二级缓存时,实体类必须实现 Serializable 接口
  • 这是 MyBatis 二级缓存的要求
  • 没有实现 Serializable 会导致序列化异常
  • 建议添加序列化版本号

开启二级缓存有什么好处

开启 MyBatis 二级缓存有以下几个主要好处:

  1. 提高查询性能:
  • 减少数据库访问次数
  • 降低数据库压力
  • 提高响应速度
  • 减少网络开销
  1. 减少数据库负载: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace
    public interface UserMapper {
       // 第一次查询会访问数据库
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);
       
       // 第二次查询相同数据会直接从缓存获取
       // 不会访问数据库
    }
  1. 适用场景:
  • 频繁查询但不常更新的数据
  • 数据量较小的表
  • 对实时性要求不高的数据
  • 多用户共享的数据
  1. 性能提升示例: java
    Apply to TestJwt.java
    // 不使用缓存
    for (int i = 0; i < 1000; i++) {
       userMapper.getUserById(1);  // 每次都会查询数据库
    }
    // 使用缓存
    for (int i = 0; i < 1000; i++) {
       userMapper.getUserById(1);  // 只有第一次查询数据库,后续从缓存获取
    }
  1. 内存使用优化: java
    Apply to TestJwt.java
    @CacheNamespace(
       size = 1024,  // 控制缓存大小
       eviction = LruCache.class  // 使用 LRU 淘汰策略
    )
    public interface UserMapper {
       // 缓存配置
    }
  1. 注意事项:
  • 缓存会占用内存
  • 需要注意缓存一致性
  • 不适合频繁更新的数据
  • 实体类需要实现 Serializable
  1. 最佳实践: java
    Apply to TestJwt.java
    @Mapper
    @CacheNamespace(
       eviction = LruCache.class,
       flushInterval = 60000,  // 定期刷新缓存
       size = 1024,  // 控制缓存大小
       readWrite = true
    )
    public interface UserMapper {
       // 适合缓存的方法
       @Select("SELECT * FROM user WHERE id = #{id}")
       User getUserById(Integer id);
       
       // 不适合缓存的方法
       @Select("SELECT * FROM user WHERE update_time > #{time}")
       List<User> getRecentUsers(Date time);
    }
  1. 使用建议:
  • 根据业务需求选择合适的缓存策略
  • 设置合适的缓存大小
  • 定期清理缓存
  • 注意缓存一致性
  1. 性能对比: text
    Apply to TestJwt.java
    不使用缓存:
    - 每次查询都访问数据库
    - 响应时间较长
    - 数据库压力大
    使用缓存:
    - 首次查询访问数据库
    - 后续查询从缓存获取
    - 响应时间短
    - 数据库压力小
  1. 总结好处:
  • 提高查询性能
  • 减少数据库访问
  • 降低数据库压力
  • 提高响应速度
  • 减少网络开销
  • 优化系统资源使用
  1. 使用场景示例: java
    Apply to TestJwt.java
    // 适合缓存的场景
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(Integer id);  // 用户基本信息
    // 不适合缓存的场景
    @Select("SELECT * FROM order WHERE user_id = #{userId}")
    List<Order> getUserOrders(Integer userId);  // 订单信息经常变化

总结:

  • 二级缓存能显著提高查询性能
  • 减少数据库访问和压力
  • 提高系统响应速度
  • 优化资源使用
  • 适合特定业务场景
  • 需要注意缓存管理

最后我们来测试一下实体类如果没有实现Serializable接口会怎么样?会不会导致序列化异常?

image.gif 编辑

可以看到没有实现Serializable接口导致出现io错误,再来试试实现Serializable接口会不会解决?

image.gif 编辑

可以看到已经不会报错了,看来不实现Serializable接口确实会导致序列化异常。

那么我们再来看看二级缓存对于查询有没有提升?

我们可以看到我第一次查询速度是614ms

image.gif 编辑

再重复查询试试

image.gif

可以看到确实有所提升

相关文章
|
缓存 NoSQL Redis
通过切面结合Redis自定义缓存注解
通过切面结合Redis自定义缓存注解
210 0
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
缓存 NoSQL Java
SSM之spring注解式缓存redis
SSM之spring注解式缓存redis
142 0
|
缓存 Java 数据库
SpringBoot缓存注解使用
Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
753 89
|
缓存 NoSQL 调度
【redis】ssm项目整合redis,redis注解式缓存及应用场景,redis的击穿、穿透、雪崩的解决方案
【redis】ssm项目整合redis,redis注解式缓存及应用场景,redis的击穿、穿透、雪崩的解决方案
439 0
|
缓存 Java 数据库
优化您的Spring应用程序:缓存注解的精要指南
优化您的Spring应用程序:缓存注解的精要指南
260 0
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
635 5
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
4256 2
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
627 2
|
缓存 NoSQL Java
Redis之与SSM集成Spring注解式缓存
Redis之与SSM集成Spring注解式缓存
200 0