• Redis与Mybatis


    作者在学习Redis整合时使用JDBC与Jedis,但是呢,现如今的环境下,Mybatis系列ORM框架是更受关注的方法,作者有一点点Mybatis基础,Mybatisplus几乎忘的差不多了,现对Redis整合Mybatis相关知识进行梳理,在进一步学习Mybatis系列知识后,再将具体代码进行补充测试。

    结合 MyBatis 和 Redis 进行缓存可以通过 MyBatis 提供的缓存机制来实现。下面的例子将指导你如何使用 MyBatis-Redis-Cache 这个库进行整合。


    基本步骤

    添加依赖: 在你的 pom.xml 文件中添加 MyBatis 和 MyBatis-Redis-Cache 的依赖。

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.mybatis.spring.bootgroupId>
    4. <artifactId>mybatis-spring-boot-starterartifactId>
    5. <version>2.1.4version>
    6. dependency>
    7. <dependency>
    8. <groupId>org.mybatis.cachesgroupId>
    9. <artifactId>mybatis-redisartifactId>
    10. <version>1.0.0version>
    11. dependency>
    12. dependencies>

    配置 Redis:application.propertiesapplication.yml 文件中配置 Redis 的相关信息。

    1. # Redis 配置
    2. spring.redis.host=你的Redis服务器地址
    3. spring.redis.port=6379

    配置 MyBatis: 在 MyBatis 的配置文件(例如 mybatis-config.xml)中开启缓存。

    1. <settings>
    2. <setting name="cacheEnabled" value="true"/>
    3. settings>

    示例

    假设你有一个 UserMapper 接口和相应的 UserMapper.xml 文件:

    UserMapper.xml 文件中开启缓存:

    1. <mapper namespace="com.example.mapper.UserMapper">
    2. <cache type="org.mybatis.caches.redis.RedisCache" />
    3. <select id="selectUserById" resultType="User">
    4. SELECT * FROM user WHERE id = #{id}
    5. select>
    6. mapper>

    在服务层使用 UserMapper

    1. @Service
    2. public class UserService {
    3. @Autowired
    4. private UserMapper userMapper;
    5. public User getUserById(int id) {
    6. // 首次调用将查询数据库
    7. // 之后的调用将直接从 Redis 缓存中获取结果
    8. return userMapper.selectUserById(id);
    9. }
    10. }

    基础代码解释与自定义缓存类

    在 MyBatis 的 Mapper XML 文件中使用 标签和属性时,这是在告诉 MyBatis 使用默认的缓存实现

    机制

    1. 初始化时的操作:

      • 当 MyBatis 初始化时,它会读取 Mapper XML 文件,并根据 XML 文件内容创建相应的 Mapper 对象。
      • 当 MyBatis 遇到 标签时,它会尝试实例化指定类型(type 属性)的缓存对象。
      • 指定的缓存类(在本例中是 com.example.cache.RedisCache)会被实例化,并且在需要缓存操作时被 MyBatis 调用
    2. 执行查询时的操作:

      • 当执行查询(如 selectUserById)时,MyBatis 会首先检查缓存是否已经包含该查询的结果。因为在定义SQL语言之前,命名空间里还声明了 这种声明会让Mybatis做出对缓存的检查。
      • 如果缓存中存在结果,MyBatis 就直接从缓存中返回结果,不再执行实际的 SQL 查询。
      • 如果缓存中不存在结果,MyBatis 会执行 SQL 查询,并将查询结果存储在缓存中以供将来使用。
    3. 关闭操作:

      • 当 MyBatis 会话结束时,所有的缓存资源应该被正确释放。

    自定义缓存类

    在使用 MyBatis 和 Redis 缓存时,如果你想要更多地控制 Redis 的详细操作,你可能需要自定义缓存处理逻辑。

    其本质就是创建一个类,实现 MyBatis 的 Cache 接口。然后就把自定义类的名字换成之前的RedisCache就行,都是一样的配置。其自定义类代码如下所示:

    1. import org.apache.ibatis.cache.Cache;
    2. import redis.clients.jedis.Jedis;
    3. import java.util.concurrent.locks.ReadWriteLock;
    4. import java.util.concurrent.locks.ReentrantReadWriteLock;
    5. public class MyRedisCache implements Cache {
    6. private final String id;
    7. private final Jedis redisClient = new Jedis("localhost", 6379);
    8. public MyRedisCache(String id) {
    9. this.id = id;
    10. }
    11. @Override
    12. public String getId() {
    13. return this.id;
    14. }
    15. @Override
    16. public void putObject(Object key, Object value) {
    17. redisClient.set(key.toString(), value.toString());
    18. }
    19. @Override
    20. public Object getObject(Object key) {
    21. return redisClient.get(key.toString());
    22. }
    23. @Override
    24. public Object removeObject(Object key) {
    25. return redisClient.del(key.toString());
    26. }
    27. @Override
    28. public void clear() {
    29. redisClient.flushDB();
    30. }
    31. @Override
    32. public int getSize() {
    33. return Integer.parseInt(redisClient.dbSize().toString());
    34. }
    35. @Override
    36. public ReadWriteLock getReadWriteLock() {
    37. return new ReentrantReadWriteLock();
    38. }
    39. }

    在 MyBatis 的 Mapper XML 文件中使用自定义缓存类:

    1. <mapper namespace="com.example.mapper.UserMapper">
    2. <cache type="com.example.cache.MyRedisCache" />
    3. <select id="selectUserById" resultType="User">
    4. SELECT * FROM user WHERE id = #{id}
    5. select>
    6. mapper>

    Cache接口实现

    类定义中,读者可能会发现,咋多了这么多成员变量和方法啊?这其实是实现org.apache.ibatis.cache.Cache接口覆盖的成员和方法。

    其中,有四个必须覆盖的方法

    1. String getId():返回缓存的标识符。每个缓存都必须有一个唯一的标识符。

    2. void putObject(Object key, Object value):将查询结果存储在缓存中。

    3. Object getObject(Object key):从缓存中获取key 指定的查询结果。

    4. void clear():清除缓存中的所有项目。

    三个可选覆盖的方法:

    • Object removeObject(Object key);
    • int getSize();
    • ReadWriteLock getReadWriteLock();

    这些方法是可选的,意味着不一定非要覆盖它们。removeObject() 用于从缓存中移除对象,但并没有被 MyBatis 核心框架调用。同样,getSize()getReadWriteLock() 也是可选的,并不是 MyBatis 核心部分的调用。这三个方法的实现依赖于你的实际缓存策略和需求。

    Cache接口源码

    为了更好地理解,作者查到16年某文章的cache源码。

    1. package org.apache.ibatis.cache;
    2. import java.util.concurrent.locks.ReadWriteLock;
    3. /**
    4. * 缓存接口
    5. * 给缓存供应商的SPI(Service Provider Interface)
    6. * 一个Cache的实例将为名称空间被创建
    7. * Cache接口的实现类必须有一个具有String类型参数的构造方法,用于接收Cache对象的id,作为其唯一标识
    8. *
    9. * mybatis将以namespace作为id调用这个构造函数创建对象
    10. *
    11. * @author Administrator
    12. *
    13. */
    14. public interface Cache {
    15. /**
    16. * 获取缓存对象的唯一标识
    17. * @return
    18. */
    19. String getId();
    20. /**
    21. * 保存key/value到缓存对象中
    22. * key可以是任何对象,但一般是CacheKey对象
    23. * value是查询结果,为List类型
    24. * @param key
    25. * @param value
    26. */
    27. void putObject(Object key, Object value);
    28. /**
    29. * 从缓存对象中获取key对应的value
    30. * @param key
    31. * @return
    32. */
    33. Object getObject(Object key);
    34. /**
    35. * 可选的方法,没有被核心框架调用,移除key对应的value
    36. * @param key
    37. * @return
    38. */
    39. Object removeObject(Object key);
    40. /**
    41. * 清空缓存
    42. */
    43. void clear();
    44. /**
    45. * 获取缓存对象中存储的键/值对的数量
    46. * 可选的方法,没有被框架核心调用
    47. */
    48. int getSize();
    49. /**
    50. * 获取读写锁
    51. * 可选的方法,从3.2.6起这个方法不再被框架核心调用
    52. * 任何需要的锁,都必须由缓存供应商提供
    53. *
    54. * @return A ReadWriteLock
    55. */
    56. ReadWriteLock getReadWriteLock();
    57. }

    是否可以新增方法?

    可以在自定义缓存类中添加其他方法。

    但是,这些额外的方法不会被 MyBatis 自动调用,它们只能在Override覆盖的方法内部调用。比如你想添加一个方法来计算 Redis 缓存的大小,你可以添加一个 size() 方法到你的自定义缓存类,并在 putObject 方法中调用它来更新缓存大小的信息。比如:

    1. public class MyRedisCache implements Cache {
    2. // ...其他方法
    3. public int size() {
    4. // 实现计算 Redis 缓存大小的逻辑
    5. return 0;
    6. }
    7. @Override
    8. public void putObject(Object key, Object value) {
    9. // 在存储对象之前或之后更新缓存大小信息
    10. // ...
    11. int currentSize = size();
    12. // ...
    13. }
    14. }

    注意,在MyBatis中:

    会被自动调用的方法:
    1. getId(): MyBatis会自动调用这个方法来获取缓存的唯一标识符。
    2. putObject(Object key, Object value): MyBatis会在将查询结果存入缓存时调用这个方法。
    3. getObject(Object key): MyBatis会在从缓存中获取对象时调用这个方法。
    4. clear(): 在执行更新、插入或删除操作时,MyBatis会调用这个方法来清空命名空间下的缓存。
    不会被自动调用的方法:
    1. removeObject(Object key): 这个方法在MyBatis核心框架中并不会被自动调用,但是你可以在自定义缓存实现中使用它。
    2. getSize(): 同样,这个方法也不会被MyBatis核心框架自动调用,除非你自己调用它。
    3. getReadWriteLock(): 从3.2.6版本开始,这个方法不再被框架核心调用。任何需要的锁,都必须由缓存提供商自行实现和管理。

    总的来说,getId(), putObject(), getObject(), 和 clear() 这四个方法是在MyBatis操作过程中会被自动调用的,其他方法(removeObject(), getSize(), getReadWriteLock()和其他非Cache接口的方法)则不会,需要根据实际情况自行调用或实现。

    示意代码

    自动调用

    考虑以下 Mapper XML 文件:

    1. <mapper namespace="com.example.mapper.UserMapper">
    2. <cache type="com.example.cache.MyRedisCache" />
    3. <select id="selectUserById" resultType="User">
    4. SELECT * FROM user WHERE id = #{id}
    5. select>
    6. mapper>

    当执行 selectUserById 查询时:

    • MyBatis 会调用 MyRedisCache 类的 getObject 方法来尝试从 Redis 缓存中获取结果。
    • 如果 getObject 返回 null(缓存未命中),MyBatis 将执行 SQL 查询并将结果通过 putObject 方法存储到 Redis 缓存中。
    • 如果 getObject 返回非 null(缓存命中),MyBatis 将直接返回缓存的结果。
    手动调用

    既可以通过藏在自动调用的函数(不过这应该不属于手动调用),也可以通过获取 SqlSessionFactoryConfiguration,然后获取特定的 Cache 对象来调用这个方法。不过貌似这种创建实例对象的方案不是很流行,具体等作者多学一点知识再说。

    下面是一个例子:

    1. SqlSessionFactory sqlSessionFactory = ... // 获取 SqlSessionFactory
    2. Configuration configuration = sqlSessionFactory.getConfiguration();
    3. Cache cache = configuration.getCache("com.example.cache.MyRedisCache"); // 使用你的 cache id
    4. int size = cache.getSize();
    5. System.out.println("Cache Size: " + size);

    在这个例子中:

    • 首先,获取了 SqlSessionFactory 的实例。
    • 然后,从 SqlSessionFactory 中获取了 Configuration 对象。
    • 接着,从 Configuration 中通过 cache id 获取了 Cache 对象。
    • 最后,调用了 getSize() 方法来获取缓存的大小。
  • 相关阅读:
    空气传导和骨传导耳机哪个好?这两种耳机有什么区别?
    在.NET 6.0中配置WebHostBuilder
    重磅来袭!豆瓣评分9.9,万人血书的多线程与高并发v2.0版本
    vue3 + ts: layout布局
    FastDFS分布式文件系统
    堪称一绝,这份70W年薪高并发架构技术分布式大量流限流PDF,再不会算我输
    基因调控网络及其模型
    Intelli IDEA java调用DLL库
    双指针的问题解法以及常见的leetcode例题。
    AUTOCAD——遮罩命令、如何使用CAD对图纸进行局部放大
  • 原文地址:https://blog.csdn.net/qq_65052774/article/details/133253089