SpringBoot整合Reids(配置文件方式)

说明

在 SpringBoot2.x 之后, 原来使用的 Jedis 被替换成了 lettuce
jedis: 采用直连, 多个线程操作的话, 是不安全的, 如果想要避免不安全, 使用 jedis pool 连接池 它更像BIO
lettuce: 采用netty 实例可以多个线程中进行共享, 不存在线程不安全的情况, 可以减少线程数据 它更像NIO

maven依赖

 <dependencies>
        <!--mybatis 依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--redis lettuce-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <!--<version>2.1.10.RELEASE</version>-->
            <!--<version>1.7.5.RELEASE</version>-->
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--<scope>runtime</scope>-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <!--<version>3.0.1</version>-->
        </dependency>
    </dependencies>

  

application.yml

server:
  port: 8080

spring:
  datasource:
    name: test
    url: jdbc:mysql://47.104.248.219:3306/redis?serverTimezone=UTC
    username: root
    password: 12345678.Lhx
    driver-class-name: com.mysql.jdbc.Driver
  main:
    allow-bean-definition-overriding: true


  ### Redis 相关配置
  redis:
    host: 47.104.248.219
    port: 6379
    timeout: 10000
  database: 0
#    lettuce:
#      pool:
#        max-active: 8
#        max-wait: -1
#        max-idle: 8
#        min-idle: 0

#    pool:
#      max-active: 8
#      max-wait: -1
#      max-idle: 8
#      min-idle: 0

mybatis:
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        #开启MyBatis的二级缓存
      cache-enabled: true
    mapper-locations: classpath:mapping/*Mapper.xml,classpath:mapping/extend/*Mapper.xml         #扫描mapper.xml
#    type-aliases-package: com.lvhx.pojo

 

redis.properties

redis.hostName=47.104.248.219
redis.port=6379
#redis.password=613613
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true

 

redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        说明: 在 SpringBoot2.x 之后, 原来使用的 Jedis 被替换成了 lettuce
        jedis: 采用直连, 多个线程操作的话, 是不安全的, 如果想要避免不安全, 使用 jedis pool 连接池 它更像BIO
        lettuce: 采用netty 实例可以多个线程中进行共享, 不存在线程不安全的情况, 可以减少线程数据 它更像NIO
    -->

    <!-- 1. 引入properties配置文件 -->
    <context:property-placeholder location="classpath:redis.properties" />

    <!-- 2. redis连接池配置-->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空闲数-->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <!--连接池的最大数据库连接数  -->
        <property name="maxTotal" value="${redis.maxTotal}"/>
        <!--最大建立连接等待时间-->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
        <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)-->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
        <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3-->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
        <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1-->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
        <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
        <!--在空闲时检查有效性, 默认false  -->
        <property name="testWhileIdle" value="${redis.testWhileIdle}"/>
    </bean>

    <!-- 3. redis连接工厂 -->
    <!--<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">-->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory" destroy-method="destroy">
        <!--<property name="poolConfig" ref="poolConfig"/>-->
        <!--IP地址 -->
        <property name="hostName" value="${redis.hostName}"/>
        <!--端口号  -->
        <property name="port" value="${redis.port}"/>
        <!--如果Redis设置有密码  -->
        <!--<property name="password" value="${redis.password}"/>-->
        <!--客户端超时时间单位是毫秒  -->
        <property name="timeout" value="${redis.timeout}"/>
    </bean>

    <!-- 4. redis操作模板,使用该对象可以操作redis  -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <!--如果不配置Serializer,那么存储的时候缺省(默认)使用String,如果用User类型存储,那么会提示错误User can't cast to String!!  -->
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <!--<property name="valueSerializer">-->
            <!--<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>-->
        <!--</property>-->
        <!--<property name="hashKeySerializer">-->
            <!--<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>-->
        <!--</property>-->
        <!--<property name="hashValueSerializer">-->
            <!--<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>-->
        <!--</property>-->
        <!--开启事务  -->
        <property name="enableTransactionSupport" value="true"/>
    </bean>

    <!-- 5.使用中间类解决RedisCache.RedisTemplate的静态注入,从而使MyBatis实现第三方缓存 -->
    <bean id="redisCacheTransfer" class="com.lvhx.util.RedisCacheTransfer">
        <property name="redisTemplate" ref="redisTemplate"/>
    </bean>



</beans>

 

start-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--<context:property-placeholder ignore-unresolvable="true" location="classpath:jdbc.properties,classpath:redis.properties" />-->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:redis.properties" />

    <import resource="redis.xml"></import>

</beans>

 

启动类

@SpringBootApplication
//此处扫描的是接口
@MapperScan("com.lvhx.dao")
@ComponentScan(basePackages = {"com.lvhx.*"})
@ImportResource("classpath:/start-config.xml")
@EnableCaching
@EnableAutoConfiguration
public class SpringbootMybatisApplication {

    //    private final Logger logger = LoggerFactory.getLogger(SpringbootMybatisApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisApplication.class, args);
        System.out.println("*****服务启动成功*****");
    }
}

 

ApplicationContextHolder

@Component
public class ApplicationContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    /**
     * 清除applicationContext静态变量.
     */
    public static void cleanApplicationContext() {
        applicationContext = null;
    }

    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
        }
    }
}

 

MybatisRedisCache

public class MybatisRedisCache implements Cache {
    private static final Logger log = LoggerFactory.getLogger(MybatisRedisCache.class);
    private String id;
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static RedisTemplate redisTemplate;
    //private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间

    public MybatisRedisCache() {}

    public MybatisRedisCache(String id) {
        System.out.println("===缓存ID = "+id);
        this.id = id;
    }

    public static void setRedisTemplate(RedisTemplate redisTemplate) {
        MybatisRedisCache.redisTemplate = redisTemplate;
    }

    private RedisTemplate<Object, Object> getRedisTemplate(){
        return ApplicationContextHolder.getBean("redisTemplate");
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        RedisTemplate redisTemplate = getRedisTemplate();
        try {
            redisTemplate.boundHashOps(getId()).put(key, value);
            log.info("[结果放入到缓存中: " + key + "=" + value+" ]");
        }catch (Exception e){
            e.printStackTrace();
            log.error("[结果放入缓存失败: " + key + "=" + value+" ]");
        }


    }

    @Override
    public Object getObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        try {
            Object value = redisTemplate.boundHashOps(getId()).get(key);
            log.info("[从缓存中获取了: " + key + "=" + value+" ]");
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("[从缓存获取失败: " + key + " ]");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        RedisTemplate redisTemplate = getRedisTemplate();
        Object value = redisTemplate.boundHashOps(getId()).delete(key);
        log.info("[从缓存删除了: " + key + "=" + value+" ]");
        return value;
    }

    @Override
    public void clear() {
        RedisTemplate redisTemplate = getRedisTemplate();
        redisTemplate.delete(getId());
        log.info("清空缓存!!!");
    }

    @Override
    public int getSize() {
        RedisTemplate redisTemplate = getRedisTemplate();
        Long size = redisTemplate.boundHashOps(getId()).size();
        return size == null ? 0 : size.intValue();
    }

    /**
     * 清理所有缓存
     */
    public void clearAll(){
        RedisTemplate redisTemplate = getRedisTemplate();
        Set keys = redisTemplate.keys("*");
        if (!ObjectUtils.isEmpty(keys)){
            redisTemplate.delete(keys);
        }
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }
}

 

RedisCacheTransfer

public class RedisCacheTransfer {
    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        MybatisRedisCache.setRedisTemplate(redisTemplate);
    }
}

 

RedisConfig

@Configuration
public class RedisConfig {

    @Autowired
    private LettuceConnectionFactory connectionFactory;

//    @Autowired
//    private JedisConnectionFactory connectionFactory;

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        initDomainRedisTemplate(redisTemplate, connectionFactory);
        return redisTemplate;
    }

    /**
     * 设置数据存入 redis 的序列化方式
     *
     * @param template
     * @param factory
     */
    private void initDomainRedisTemplate(RedisTemplate<String, Object> template, LettuceConnectionFactory factory) {
        // 定义 key 的序列化方式为 string
        // 需要注意这里Key使用了 StringRedisSerializer,那么Key只能是String类型的,不能为Long,Integer,否则会报错抛异常。
        StringRedisSerializer redisSerializer = new StringRedisSerializer();
        template.setKeySerializer(redisSerializer);
        // 定义 value 的序列化方式为 json
        @SuppressWarnings({"rawtypes", "unchecked"})
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setValueSerializer(jackson2JsonRedisSerializer);

        //hash结构的key和value序列化方式
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.setEnableTransactionSupport(true);
        template.setConnectionFactory(factory);
    }
}

 OrderController

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;

    /**
     * 查找所有order
     * @return
     */
    @RequestMapping(value = {"/findAll"}, produces = {"application/json;charset=UTF-8"}, method = RequestMethod.GET)
    public List<Order> findAll() {
        List<Order> list = orderService.findAllOreder();
        return list;
    }

    /**
     * 测试插入数据
     */
    @RequestMapping(value = {"/testInsert"})
    public void testInsert() {
        Order order = new Order();
        order.setId(String.valueOf(System.currentTimeMillis()));
        order.setName(String.valueOf(System.currentTimeMillis()));
        order.setMessageId(String.valueOf(System.currentTimeMillis()));
        orderService.testInsert(order);
    }

    /**
     * 清理所有缓存
     */
    @RequestMapping(value = {"/clearCache"})
    public void clearCache() {
        orderService.clearCache();
    }
}

 

OrderService

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderExtednMapper orderExtednMapper;

    public List<Order> findAllOreder(){
        List<Order> allInfo = orderExtednMapper.getAllInfo();
        return allInfo;
    }

    public void testInsert(Order order){
        orderMapper.insertSelective(order);
    }

    public void clearCache(){
        MybatisRedisCache mybatisRedisCache = new MybatisRedisCache();
        mybatisRedisCache.clearAll();
    }
}

 

OrderMapper.xml

<?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.lvhx.dao.OrderMapper" >
  <!-- 开启基于redis的二级缓存 -->
  <cache type="com.lvhx.util.MybatisRedisCache"/>
</mapper>

 

gitee地址

git@gitee.com:lvhongxu/springboot-redis.git

 

posted @ 2021-11-26 10:29  微醺的小布  阅读(290)  评论(0编辑  收藏  举报