SpringBoot-Redis联合Mybatis实现分布式缓存

SpringBoot-Redis联合Mybatis实现分布式缓存

相关依赖

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>

配置文件

关于Redis的主从复制、哨兵、集群的配置:Redis搭建主从复制、哨兵集群

spring.redis.host= [你redis服务所在的主机ip]
spring.redis.port=[你redis服务端口 单机一般是6379]
# 单机配置
#spring.redis.database=1
#server.port=8899

#如果redis采用哨兵机制,改成连接哨兵的方式
#sentinel为配置文件中自定的master节点名称 
spring.redis.sentinel.master=mymaster
#如果有多个哨兵(集群) 则配置各自的节点地址  ip + 端口
spring.redis.sentinel.nodes=[你redis服务所在的主机ip]:[哨兵端口 单个的话一般是26379]



#数据源配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

#用 / 会报错
mybatis.mapper-locations=classpath:com.junsir.mapper/*.xml
mybatis.type-aliases-package=com.junsir.entity

#打印数据库的操作
logging.level.com.junsir.dao=debug

缓存实体类

这是我们要向Redis中缓存的对象

@Data
@Accessors(chain = true)
public class Person implements Serializable {

    private String personId;
    private String name;
    private Integer gender;
    private String personAddr;
    private Date birthday;
}

Mybatis Dao & Mapper

定义了一个方法 返回所有Person对象,假设我们的缓存生效,将无法看到查询数据库的操作日志,而是显示Cache hit表示击中缓存

public interface PersonDao {
    List<Person> findAll();
}

Mapper:

直接启用Mybatis的<-cache>标签,缓存是本机缓存,所以我们需要实现自定义Redis缓存

<mapper namespace="com.junsir.dao.PersonDao">
  <!--  开启二级缓存 需要entity开启序列化 type指定自定义缓存策略 -->
  <cache type="com.junsir.cache.RedisCache"/>
  <!-- 关联查询时,需要保证各方缓存的数据都是最新的,采用共享缓存方案 -->
   <!--  <cache-ref namespace="com.junsir.dao.PersonDao"/>-->
  <!--  findAll -->
  <select id="findAll"  resultType="Person">
    select person_id,name,gender from person
  </select>
</mapper>

RedisCache.java:

此类需要实现org.apache.ibatis.cache.Cache接口,才可以在Mapper中进行指定

/**
 * 本类由mybatis初始化 启动时并无法由spring容器管理(盲猜参数无法传递id),故无法注入拿到RedisTemplate
 * 要拿到RedisTemplate 需要动下工厂 在工厂启动时拿到RedisTemplate
 *
 * 实现细节:
 * 多表关联查询下的内容保持最新 - 由于DB增删改只会使Redis清空对应key的缓存 所以目的就是让有关联的缓存数据同时进同时出
 *
 * 实现完毕之后的优化问题:
 * 1.key过长会影响redis性能,采用MD5算法对key进行处理,这里利用的是MD5加密算法的唯一性
 * */
public class RedisCache implements Cache {

    //自定义Cache必要条件
    private final String id;

    //根据断点 : id:mapper的namespace
    public RedisCache(String id) {
        this.id = id;
    }

    //返回cache的唯一标识
    @Override
    public String getId() {
        return this.id;
    }

    //重点实现 加入缓存
    @Override
    public void putObject(Object key, Object value) {
        System.out.println("key================" + key + "value ===================" + value);
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.opsForHash().put(id.toString(),keyToMd5(key.toString()),value);
    }

    //重点实现 查询缓存
    @Override
    public Object getObject(Object key) {
        System.out.println("key================" + key );
        RedisTemplate redisTemplate = getRedisTemplate();
        return redisTemplate.opsForHash().get(id.toString(),keyToMd5(key.toString()));
    }

    //根据指定的key删除缓存 目前没有实现
    @Override
    public Object removeObject(Object o) {
        return null;
    }

    //清空缓存 执行增删改的时候都会进行clear
    @Override
    public void clear() {

        RedisTemplate redisTemplate = getRedisTemplate();
        //清空缓存
        redisTemplate.delete(id.toString());
    }

    //计算缓存数量
    @Override
    public int getSize() {

        RedisTemplate redisTemplate = getRedisTemplate();
        //获取哈希中的键值对数量
        return redisTemplate.opsForHash().size(id.toString()).intValue();
    }

    //统一加工redisTemplate 并返回
    public RedisTemplate getRedisTemplate(){
        //获取redisTemplate
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        //设置序列化策略
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }


    //优化: 对key做MD5处理
    public String keyToMd5(String key){
        return  DigestUtils.md5DigestAsHex(key.getBytes());
    }

}

Test.java

在确保Redis服务正常启动后,运行以下测试程序

@SpringBootTest(classes = RedisApplication.class)
public class TestPersonService {

    @Autowired
    private PersonService personService;

    @Test
    public void test(){
        //理想状态下 第一次查询 Redis中无相关数据
        personService.findAll().forEach(p-> System.out.println("p==" + p));
        System.out.println("===============================");
        //理想状态下 第一次查询的结果已经存在于Redis 此时查询不会再经过数据库
        personService.findAll().forEach(p-> System.out.println("p==" + p));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值