Redis

Redis

Springboot集成Redis

redis常常作为项目中的缓存机制存在。

1、加入依赖

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettucegroupId>
                    <artifactId>lettuce-coreartifactId>
                exclusion>
            exclusions>
        dependency>
        <dependency>
            <groupId>redis.clientsgroupId>
            <artifactId>jedisartifactId>
        dependency>

关于lettuce以及jedis都是Redis的客户端框架。Redis存在有三个客户端框架,还有一个是Redisson。

2、修改配置文件

spring:
  redis:
    database: 0
    host: ???
    port: ???
    password:
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
    timeout: 0

下一个任务就是要保证你的Redis数据库的连接使用,这里在配置文件中进行配置即可。

3、继承CachingConfigurerSupport自定义缓存配置

/**
 * 自定义缓存配置文件,继承CachingConfigurerSupport
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    public RedisConfig() {
        super();
    }

    /**
     * 指定使用哪一种缓存机制,用redis连接工厂创建一个redis缓存机制(RedisCacheManager)
     * @return
     */
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisCacheManager rcm=RedisCacheManager.create(factory);
        return rcm;
    }

    @Override
    public CacheResolver cacheResolver() {
        return super.cacheResolver();
    }

    /**
     * 指定默认的key生成方式
     * @return
     */

    @Override
    public KeyGenerator keyGenerator() {
        KeyGenerator keyGenerator=new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                StringBuilder sb=new StringBuilder();
                sb.append(o.getClass().getName());
                sb.append(method.getName());
                for(Object obj:objects){
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
        return keyGenerator;
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return super.errorHandler();
    }

    /**
     * 使用fastJson作为默认序列化方式,否则需要对实体类进行序列化
     * @param factory
     * @return
     */

    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
        //建议redis连接操作
        redisTemplate.setConnectionFactory(factory);
        //新定义一个fastJson序列化方式
        GenericFastJsonRedisSerializer genericFastJsonRedisSerializer=new GenericFastJsonRedisSerializer();
        //配置redis连接
        redisTemplate.setDefaultSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
        redisTemplate.setKeySerializer(genericFastJsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    /**
     * 转换返回的object为json
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters(){
        //定义一个converter转换器
        FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();
        //添加fastJSON的配置信息
        FastJsonConfig fastJsonConfig=new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        //在converter中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //将convert添加到converters中
        HttpMessageConverter<?> converter=fastConverter;
        return new HttpMessageConverters(converter);
    }
}

4、Springboot主类中开启缓存并且使用自定义默认缓存配置

@Import(RedisConfig.class)
@EnableCaching

5、在service层加入缓存的概念

在原本的数据库操作的service层实现类加入缓存的概念即可。

@Service
public class UserServiceImpl implements UserService {

    private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Resource
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 先写入数据库中再写入缓存中
     * @param record
     * @return
     */
    @Transactional
    @Override
    public int insert(User record) {
        //存入数据库
        ValueOperations<String,User> operations=redisTemplate.opsForValue();
        int result=userMapper.insert(record);
        if(result!=0){
            String key="user_"+record.getId();
            operations.set(key,record);
            logger.info("---------写入数据{}到缓存----------",record);
        }
        return result;

    }

    /**
     * 先写入数据库中,再写入缓存中
     * @param record
     * @return
     */

    @Override
    public int insertSelective(User record) {
        int result=userMapper.insertSelective(record);
        ValueOperations operations=redisTemplate.opsForValue();
        if(result!=0){
            String key="user_"+record.getId();
            operations.set(key,record);
            logger.info("---------写入数据{}到缓存----------",record);
        }
        return result;
    }

    /**
     * 读取数据的时候先从缓存中读取数据,如果缓存中不存在,再从数据库中读出,并存入缓存
     * @param id
     * @return
     */
    @Override
    public User selectById(Integer id) {
        ValueOperations<String,User> operations=redisTemplate.opsForValue();
        String key="user_"+id;
        boolean hasKey=redisTemplate.hasKey(key);
        if(hasKey){//缓存中存在
            User user=operations.get(key);
            logger.info("-------从缓存中获取该数据{}----------",user.toString());
            return user;
        }else{
            User user=userMapper.selectById(id);
            logger.info("-------------从表中获取数据{}------------",user.toString());
            logger.info("------------将数据写入缓存-----------");
            operations.set(key,user,5, TimeUnit.HOURS);
            return user;
        }

    }

    @Override
    public List<User> selectAll() {
        return userMapper.selectAll();
    }

    @Override
    //先删除表中的数据,然后删除缓存
    public int deleteById(Integer id) {
       int result= userMapper.deleteById(id);
       String key="user_"+id;
       if(result!=0){
           boolean hasKey=redisTemplate.hasKey(key);
           if(hasKey){
               redisTemplate.delete(key);
               logger.info("----------从缓存中删除:"+key+"-------------");
           }
       }
       return result;
    }

    @Override
    public int updateById(User user) {
        ValueOperations<String,User> operations=redisTemplate.opsForValue();
        int result=userMapper.updateById(user);
        if(result!=0){//更新表成功
            String key="user_"+user.getId();
            boolean hasKey=redisTemplate.hasKey(key);
            if(hasKey){
                redisTemplate.delete(key);
                logger.info("----------从缓存中删除------------");
            }
            User newUser=userMapper.selectById(user.getId());
            if(newUser!=null){
                operations.set(key,newUser,3,TimeUnit.HOURS);
                System.out.println("----------删除之后,更新缓存------------");
            }
        }
        return result;
    }
}

6、附录—关于spring3中注解的问题

@CacheConfig

主要用于配置该类中会用到的一些共用的缓存配置。

@CacheConfig(cacheNames = "users")//表明该类中所有缓存都存在users集合中

@Cacheable

应用到读取数据的方法上,即可缓存的方法,如查找方法,先从缓存中读取,如果没有再调用相应方法获取数据,然后把数据添加到缓存中。

  • **value、cacheNames:**两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
  • **key:**缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = “#p0”):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
  • **condition:**缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = “#p0”, condition = “#p0.length() < 3”),表示只有当第一个参数的长度小于3的时候才会被缓存。
  • **unless:**另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
  • **keyGenerator:**用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
  • **cacheManager:**用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
  • **cacheResolver:**用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。
@Cacheable(value = "user", key = "#id")//在user集合中,建是id的值

@CachePut

应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存.

@CachePut(value = "user", key = "#id")//在user集合中,建是id的值

@CacheEvict

应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据

  • allEntries:非必需,默认为false。当为true时,会移除所有数据
  • beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。

@Caching

组合做个cache注解使用

@Caching( 
    put = { 
        @CachePut(value = "user", key = "#user.id"), 
        @CachePut(value = "user", key = "#user.username"), 
        @CachePut(value = "user", key = "#user.age") 
   } 
}

参考文章:

https://www.cnblogs.com/kingsonfu/p/10409596.html
https://www.cnblogs.com/yixianyixian/p/7427878.html

你可能感兴趣的:(redis,spring)