1. 程式人生 > >springboot2.x 和用redis做快取的整合,有專案地址的呦

springboot2.x 和用redis做快取的整合,有專案地址的呦

1. springboot和用redis做快取的整合

這裡要整合的是springboot2.x和redis,所以你要把你的springboot 版本在開始之前換成springboot2.0之後的

具體怎麼換其實就是換一下版本號,不換的話後面會有很多問題,樓主踩了無數坑

專案地址   https://github.com/HouChenggong/springboot_redis_cache.git

傳送門

1.1 換版本號

//就是把version換成2.0以後的

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

1.2 新增maven的依賴

還會用到這三個maven依賴,總之先新增上把,後面會有用到的

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>

1.3 資料庫連線新增redis

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 2
    timeout: 60s  # 資料庫連線超時時間,2.0 中該引數的型別為Duration,這裡在配置的時候需要指明單位
    # 連線池配置,2.0中直接使用jedis或者lettuce配置連線池
    jedis:
      pool:
        # 最大空閒連線數
        max-idle: 8
        # 最小空閒連線數
        min-idle: 0
        # 等待可用連線的最大時間,負數為不限制
        max-wait:  -1s
        # 最大活躍連線數,負數為不限制
        max-active: -1
 

1.3 然後開啟reidis快取

package com.pf.org.cms;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;

import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.*;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.time.Duration;

@EnableScheduling
@SpringBootApplication
@EnableCaching
public class CmsApplication {


    @Autowired
    private RedisConnectionFactory connectionFactory = null ;
    @Autowired
    private RedisTemplate redisTemplate ;


    //自定義初始化
    @PostConstruct
    public void init(){
        initRedisTemplate();
    }

    //改變redistemplate對於鍵的序列化策略
    private void initRedisTemplate(){
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);

    }

    public static void main(String[] args) {
        SpringApplication.run(CmsApplication.class, args);
    }
}

2. 新增程式碼實現

2.1 Entity

注意這裡實現了序列化

public class MyRedisDO implements Serializable {


    private  Integer id ;

    private  String name ;


    private  String note ;
    
    getter and setter ....
    }

2.2 Mapper mapper.xml

import com.pf.org.cms.hcg.system.bean.MyRedisDO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface MyRedisMapper {

    int del(Integer id);

    int insert(MyRedisDO record);

    MyRedisDO selectById(Integer id);

   //獲取使用者id和user_name
    List<MyRedisDO> selectAll();

    int update(MyRedisDO record);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pf.org.cms.hcg.system.mapper.MyRedisMapper">
  <resultMap id="BaseResultMap" type="com.pf.org.cms.hcg.system.bean.MyRedisDO">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="note" jdbcType="VARCHAR" property="note" />
  </resultMap>

  <sql id="Base_Column_List">
    id, name, note
  </sql>


  <select id="selectById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from myredis
    where id = #{id,jdbcType=INTEGER}
  </select>

  <insert id="insert" useGeneratedKeys="true"  keyColumn="id" keyProperty="id" parameterType="com.pf.org.cms.hcg.system.bean.MyRedisDO">
    insert into myredis (name ,note) values ( #{name,jdbcType=VARCHAR} ,#{note,jdbcType=VARCHAR})
  </insert>

  <update id="update" parameterType="com.pf.org.cms.hcg.system.bean.MyRedisDO">
    update  myredis set name =#{name,jdbcType=VARCHAR} , note =#{note,jdbcType=VARCHAR} WHERE  id =#{id}
  </update>

  <select id="selectAll" resultMap="BaseResultMap">
      select  * from  myredis
  </select>


  <delete id="del" parameterType="java.lang.Integer">
    delete  from  myredis
    where id =#{id}
  </delete>
</mapper>

2.3 service serviceImpl

public interface MyRedisService {
    MyRedisDO getById(Integer id);

    int delById(Integer id);

    MyRedisDO update(MyRedisDO myRedisDO);

    MyRedisDO insert(MyRedisDO myRedisDO);

    List<MyRedisDO> getAll();
}

注意@Service 、@Transactional和方法裡面的

//針對查詢的,如果快取有要查詢的值,直接從快取中取,不進行方法查詢
//如果快取中沒有,查詢出來的資料,放到快取中
@Cacheable(value = "redisCache", key = "'redisMyid'+#id")
// 將方法返回結果放到快取中,一般用於更新
@CachePut(value = "redisCache", key = "'redisMyid'+#myRedisDO.id")
 //刪除,beforeInvocation預設是false,表示在方法執行前或者方法執行後刪除,一般也都是執行後刪除
 //所以一般是false
 @CacheEvict(value = "redisCache",key = "'redisMyid'+#id", beforeInvocation = false)
至於裡面的value和key不細說,可以百度一下
package com.pf.org.cms.hcg.system.service.impl;


import com.pf.org.cms.hcg.system.bean.MyRedisDO;
import com.pf.org.cms.hcg.system.mapper.MyRedisMapper;
import com.pf.org.cms.hcg.system.service.MyRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Transactional
public class MyRedisServiceImpl implements MyRedisService {
    @Autowired
    private MyRedisMapper myRedisMapper;

    @Override
    @Cacheable(value = "redisCache", key = "'redisMyid'+#id")
    public MyRedisDO getById(Integer id) {
        System.out.println("查詢"+new Date());
        return myRedisMapper.selectById(id);
    }

    @Override
    @CacheEvict(value = "redisCache",key = "'redisMyid'+#id", beforeInvocation = false)
    public int delById(Integer id) {
        return myRedisMapper.del(id);
    }

    @Override
    @CachePut(value = "redisCache", key = "'redisMyid'+#myRedisDO.id")
    public MyRedisDO update(MyRedisDO myRedisDO) {
        myRedisMapper.update(myRedisDO);
        return myRedisDO;
    }

    @Override
    @CachePut(value = "redisCache", key = "'redisMyid'+#myRedisDO.id")
    public MyRedisDO insert(MyRedisDO myRedisDO) {
        myRedisMapper.insert(myRedisDO);
        return myRedisDO;
    }

    @Override
    public List<MyRedisDO> getAll() {
        return myRedisMapper.selectAll();
    }
}

2.4 controller

package com.pf.org.cms.hcg.system.controller;


import com.pf.org.cms.hcg.system.bean.MyRedisDO;
import com.pf.org.cms.hcg.system.service.MyRedisService;
import com.pf.org.cms.manage.RedisManager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author xiyou
 * @create 2017-11-21 17:08
 * @desc 系統管理控制層
 **/
@Api("使用者管理的控制層")
@Controller
@RequestMapping("/redis/*")
public class RedisTestController {


    @Autowired
    RedisManager redisManager;

    @Autowired
    MyRedisService myRedisService;


    private static final Logger log = LoggerFactory.getLogger(UserController.class);


    @ApiOperation(value = "Redis測試介面", notes = "swagger測試介面")
    @RequestMapping(value = "/demo", method = RequestMethod.GET)
    @ResponseBody
    public String testRedis(
            @RequestParam("key") String key) {
        System.out.println("入參key為:" + key);
        String s = "查詢結果為:" + redisManager.getStr(key);
        return s;
    }


    @ApiOperation(value = "Redis測試介面,Insert", notes = "Insert")
    @RequestMapping(value = "/demo/insertRedis", method = RequestMethod.GET)
    @ResponseBody
    public String redis1(
            @RequestParam("name") String name, @RequestParam("note") String note) {
        MyRedisDO myRedisDO = new MyRedisDO();
        myRedisDO.setName(name);
        myRedisDO.setNote(note);
        myRedisService.insert(myRedisDO);
        return "ok";
    }

    @ApiOperation(value = "Redis測試介面,get", notes = "get")
    @RequestMapping(value = "/demo/getRedis", method = RequestMethod.GET)
    @ResponseBody
    public String ge(
            @RequestParam("id") Integer id) {

        MyRedisDO redisDO = myRedisService.getById(id);
        MyRedisDO redisDO1 = myRedisService.getById(id);
        return redisDO.toString() + redisDO1.toString();
    }


    @ApiOperation(value = "Redis測試介面,del", notes = "del")
    @RequestMapping(value = "/demo/delRedis", method = RequestMethod.GET)
    @ResponseBody
    public int del(
            @RequestParam("id") Integer id) {

        int success = myRedisService.delById(id);
        return success;
    }

    @ApiOperation(value = "Redis測試介面,update", notes = "update")
    @RequestMapping(value = "/demo/updateRedis", method = RequestMethod.GET)
    @ResponseBody
    public MyRedisDO update(
            @RequestParam("id") Integer id) {
        MyRedisDO myRedisDO = myRedisService.getById(id);
        myRedisDO.setNote("更改");
        myRedisDO.setName("更改");
        myRedisService.update(myRedisDO);
        return myRedisDO;
    }
}


2.5 放開shiro攔截的介面

放開shiro攔截的介面,在shiroConfiguration裡面
        filterChainDefinitionMap.put("/demo/**", "anon");
        filterChainDefinitionMap.put("/redis/**", "anon");
//訪問進行介面測試
http://localhost:8080/swagger-ui.html#!/
http://localhost:8080/swagger-ui.html#!/redis-test-controller/geUsingGET

查詢結果:

我們發現它儲存的特別複雜而且沒有過期時間,我們現在自定義redisCacheManager快取管理器來管理

2.6 自定義快取管理器來設定快取時間並禁止字首

在原來的application啟動類裡面新增

    @Bean(name = "redisCacheManager")
    public RedisCacheManager initRedisCacheManager(){
        //redis加鎖的寫入器
        RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
        //啟動redis快取的預設配置
        RedisCacheConfiguration configuration =RedisCacheConfiguration.defaultCacheConfig();
        //設定JDK序列化器
        configuration=configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));
        //禁止字首
        configuration =configuration.disableKeyPrefix();
        //設定10Min超時
        configuration= configuration.entryTtl(Duration.ofMinutes(10));
        //建立redis快取管理器
        RedisCacheManager redisCacheManager = new RedisCacheManager(writer,configuration);
        return redisCacheManager ;

    }

結果如圖:

至於亂碼的問題,我們下期再說

專案地址   https://github.com/HouChenggong/springboot_redis_cache.git

傳送門