前言:
上篇最初也整合了redis,后来发现有问题,删除了Redis缓存相关的片段。先说一下问题:
1、User实体类具有id,name,birthday及description属性,并且设置id为36位uuid唯一标识,按照操作习惯,查询信息时,基本不会按照id取查询,通常更习惯于使用name查询;
2、更新、删除操作一般按照唯一标识的id作为条件操作(当数据库表中存在相同name的不同记录时,按name字段删除可能不安全)。
对于新手(大神看看笑笑就可以了(* ̄︶ ̄))这样就带来了一个问题:更新、删除都是按照id参数操作,再整合了redis作为缓存的时候,也只会同步更新按照id作为参数的相应更新、删除方法,而当使用name查询的时候,依旧得到的是旧的缓存记录。
经过一天的资料查找及对springboot @Cache相关的注解学习,终于实现了初步的增加、查找、更新及删除的数据库与缓存同步(暂未深入研究缓存更新机制以及更新时由于并发操作带来的数据同步问题)。
以下为缓存引入的相关代码,在上一篇的基础上增加redis配置及服务相关类:
1、RedisConfig类
/**
*
*/
package com.test.user.redisConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author Administrator
*
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
/**
* 注入RedisConnectionFactory
*/
@Autowired
RedisConnectionFactory redisConnectionFactory;
/**
* 实例化RedisTemplate对象
*/
@Bean
public RedisTemplate<String,Object> functionDomainRedisTemplate(){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<String, Object>();
initDomainRedisTemplate(redisTemplate,redisConnectionFactory);
return redisTemplate;
}
/**
* 设置数据存入redis的序列化方式
* @param redisTemplate
* @param redisConnectionFactory2
*/
private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate,RedisConnectionFactory factory) {
// TODO Auto-generated method stub
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(factory);
}
/**
* 缓存 管理器
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
CacheManager cacheManager = new RedisCacheManager(redisTemplate);
return cacheManager;
}
/**
* 实例化HashOperations对象,可以使用Hash类型操作
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String,String,Object> hashOperations(RedisTemplate<String,Object>redisTemplate){
return redisTemplate.opsForHash();
}
/**
* 实例化ValueOperations对象,可使用String操作
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String,Object> valueOperations(RedisTemplate<String,Object> redisTemplate){
return redisTemplate.opsForValue();
}
/**
* 实例化ListOperations对象,可使用List操作
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String,Object> listOperations(RedisTemplate<String,Object> redisTemplate){
return redisTemplate.opsForList();
}
/**
* 实例化SetOperations对象,可使用Set操作
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String,Object> setOperations(RedisTemplate<String,Object> redisTemplate){
return redisTemplate.opsForSet();
}
/**
* 实例化ZSetOperations对象,可使用ZSet操作
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String,Object> zSetOperations(RedisTemplate<String,Object> redisTemplate){
return redisTemplate.opsForZSet();
}
}
2、RedisService类
package com.test.user.service;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author Administrator
*
*/
@Service
public abstract class RedisService<T> {
/**
* 实例化RedisTemplate对象
*/
@Autowired
protected RedisTemplate<String,Object> redisTemplate;
/**
* 定义Hash结构操作存储实体对象
*/
@Resource
protected HashOperations<String,String,T> hashOperations;
/**
* 定义Hash表redis key的名称
* @return
*/
protected abstract String getRedisKey();
/**
*
* 在相应Hash表中添加键值对key:Object(domain)
* @param key
* @param domain
* @param expire
*/
public void put(String key,T domain,long expire) {
hashOperations.put(getRedisKey(), key, domain);
if(expire!=1) {
redisTemplate.expire(getRedisKey(), expire, TimeUnit.SECONDS);
}
}
/**
* 在相应Hash表中删除key名称元素
* @param key
*/
public void remove(String key) {
hashOperations.delete(getRedisKey(), key);
}
/**
* 在相应Hash表中查询key名称的元素
* @param key
* @return
*/
public T get(String key) {
return hashOperations.get(getRedisKey(), key);
}
/**
* 获取相应Hash表下的所有实体对象
* @return
*/
public List<T> getAll(){
return hashOperations.values(getRedisKey());
}
/**
* 查询在相应Hash表下所有key名称
* @return
*/
public Set<String> getKeys(){
return hashOperations.keys(getRedisKey());
}
/**
* 判断在相应Hash表下key是否存在
* @param key
* @return
*/
public boolean isKeyExists(String key) {
return hashOperations.hasKey(getRedisKey(), key);
}
/**
* 查询相应Hash表的所有缓存
* @return
*/
public long count() {
return hashOperations.size(getRedisKey());
}
public void empty() {
Set<String> set=hashOperations.keys(getRedisKey());
set.stream().forEach(key->hashOperations.delete(getRedisKey(), key));
}
}
3、RedisServiceImpl类
/**
*
*/
package com.test.user.service.impl;
import org.springframework.stereotype.Service;
import com.test.user.entity.User;
import com.test.user.service.RedisService;
/**
* @author Administrator
*
*/
@Service("RedisService")
public class RedisServiceImpl extends RedisService<User>{
private static final String REDIS_KEY="USER_KEY";
protected String getRedisKey() {
return REDIS_KEY;
}
}
4、UserServiceImpl 类,增加Redis缓存@Cache相关的注解实现缓存:
package com.test.user.service.impl;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import com.test.user.dao.UserDao;
import com.test.user.entity.User;
import com.test.user.service.UserService;
/**
* UserService逻辑实现类
*
*/
@Service("UserService")
//@CacheConfig(cacheNames="userCache")
//@Transactional(propagation=Propagation.REQUIRED, readOnly=false, rollbackFor=Exception.class)
public class UserServiceImpl implements UserService {
private static final Logger LOGGER= LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
private UserDao userDao;
@Resource
private RedisServiceImpl redisService;
// @Autowired
// private RedisTemplate redisTemplate;
//
/**
* 获取User逻辑:如缓存存在则从换从取值,否则从DB中获取,插入缓存
*/
// @Cacheable(value="userCache") 返回所有对象的方法,不应使用缓存?其他更新操作只添加\修改一个对象,此方法为返回对象集合,不会随着其他缓存中某一个对象更新改变
public List<User> showAll() {
return userDao.showAll();
}
@Cacheable(value="userCache",key="#name")//插入缓存,以name为key,对应user为value
public List<User> selectByName(String name){
List<User> user= userDao.selectByName(name);
return user;
}
@Cacheable(value="userCache",key="#id")//插入缓存,以id为key,对应user为value
public User selectByID(String id) {
User user=userDao.selectByID(id);
return user;
}
@Caching(put= {
@CachePut(value="userCache",key="#user.id"),
@CachePut(value="userCache",key="#user.name")
}) //添加新user对象时,分别在redis数据库中增加以id及name作为key的user缓存
public void addUser(User user){
userDao.addUser(user);
}
@Caching(
evict= {
@CacheEvict(value="userCache",key="#user.id",allEntries=false),
@CacheEvict(value="userCache",key="#user.name",allEntries=false)
}) //引入多层缓存清除:根据id(Redis:key)更新用户信息后,同步的更新id对应的name(Redis:key)查询条件的缓存对象(Redis:value)
public void updateByID(User user) {
userDao.updateByID(user);
}
@Caching(
evict= {
@CacheEvict(value="userCache",key="#id",allEntries=false),
@CacheEvict(value="userCache",key="#user.name",allEntries=true)
}) //引入多层缓存清除:根据id删除用户信息后,同步的删除id对应的name查询条件的缓存
public void deleteByID(String id) {
userDao.deleteByID(id);
}
}
经过试验,这样就可以实现Redis作为缓存,初步可以同步mysql数据库和redis数据库缓存了。图就不贴了,跟上一篇效果一样只不过实现了redis数据库作为缓存。