SpringDataRedis
1. 项目常见问题思考
对于首页每天有大量的人访问,对数据库造成很大的访问压力,甚至是瘫痪。那如何解决呢?我们通常的做法有两种:一种是数据缓存、一种是网页静态化。
2. Redis
redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写。企业开发通常采用Redis来实现缓存。同类的产品还有memcache 、memcached 、MongoDB等。
3. Jedis
Jedis是Redis官方推出的一款面向Java的客户端,提供了很多接口供Java语言调用。可以在Redis官网下载,当然还有一些开源爱好者提供的客户端,如Jredis、SRP等等,推荐使用Jedis。
4. Spring Data Redis
Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现。
spring-data-redis针对jedis提供了如下功能:
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
5.配置
导入依赖
<!-- 缓存 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
redis-config.properties
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.database=0
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
applicationContext-redis.xml
<context:property-placeholder location="classpath*:properties/*.properties" />
<!-- redis 相关配置
maxIdle :最大空闲数
maxWaitMillis:连接时的最大等待毫秒数
testOnBorrow:在提取一个jedis实例时,是否提前进行验证操作;如果为true,则得到的jedis实例均是可用的;
-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
6. API
//简单value
//设置key-value
redisTemplate.boundValueOps("name").set("hrh");
//通过key获取值
String str = (String) redisTemplate.boundValueOps("name").get();
//通过key删除值 删除后key还存在 value为null
redisTemplate.delete("name");
//set 无序 不可重复
redisTemplate.boundSetOps("nameset").add("曹操");
redisTemplate.boundSetOps("nameset").add("刘备");
redisTemplate.boundSetOps("nameset").add("孙权");
//获取指定set中的所有value 因为是不可重复的 所以返回值为set
Set members = redisTemplate.boundSetOps("nameset").members();
//删除set中的某一个值
redisTemplate.boundSetOps("nameset").remove("孙权");
//删除整个set集合的值 set还在
redisTemplate.delete("nameset");
//list 有序 可重复
//右压栈 后添加的对象排在后边 [刘备, 关羽, 张飞]
redisTemplate.boundListOps("namelist1").rightPush("刘备");
redisTemplate.boundListOps("namelist1").rightPush("关羽");
redisTemplate.boundListOps("namelist1").rightPush("张飞");
//返回前10条数据
List list = redisTemplate.boundListOps("namelist1").range(0, 10);
//根据索引查询元素
String s = (String) redisTemplate.boundListOps("namelist1").index(1);
//移除某个元素 第一个参数为移除的个数 因为list是可重复的,所以可能会有重复值
redisTemplate.boundListOps("namelist1").remove(1, "关羽");
//hash
redisTemplate.boundHashOps("namehash").put("a", "唐僧");
redisTemplate.boundHashOps("namehash").put("b", "悟空");
redisTemplate.boundHashOps("namehash").put("c", "八戒");
redisTemplate.boundHashOps("namehash").put("d", "沙僧");
//获得hash中所有的key 因为key是不重复的 所以返回set
Set s = redisTemplate.boundHashOps("namehash").keys();
//获得hash中所有的value
List values = redisTemplate.boundHashOps("namehash").values();
//根据key获得value 悟空
Object object = redisTemplate.boundHashOps("namehash").get("b");
//根据key移除值
redisTemplate.boundHashOps("namehash").delete("c");
7.引入service
任何增删改都要清空redis
在查询时重新给redis赋值
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
* 查询全部
*/
@Override
public List<TbContent> findAll() {
TbContentExample example = new TbContentExample();
example.setOrderByClause("sort_order");
return contentMapper.selectByExample(example);
}
/**
* 按分页查询
*/
@Override
public PageResult findPage(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
TbContentExample example = new TbContentExample();
example.setOrderByClause("sort_order");
Page<TbContent> page= (Page<TbContent>) contentMapper.selectByExample(example);
return new PageResult(page.getTotal(), page.getResult());
}
/**
* 增加
*/
@Override
public void add(TbContent content) {
contentMapper.insert(content);
//清空缓存
redisTemplate.boundHashOps("contentList").delete(content.getCategoryId());
}
/**
* 修改
*/
@Override
public void update(TbContent content){
TbContent tbContent = contentMapper.selectByPrimaryKey(content.getId());
redisTemplate.boundHashOps("contentList").delete(content.getCategoryId());
contentMapper.updateByPrimaryKey(content);
if(content.getCategoryId()!=tbContent.getCategoryId()){
redisTemplate.boundHashOps("contentList").delete(tbContent.getCategoryId());
}
}
/**
* 根据ID获取实体
* @param id
* @return
*/
@Override
public TbContent findOne(Long id){
return contentMapper.selectByPrimaryKey(id);
}
/**
* 批量删除
*/
@Override
public void delete(Long[] ids) {
HashSet<Long> hashSet = new HashSet<>();
//遍历得到所有需要修改的categoryId 去重
for (Long id : ids) {
TbContent tbContent = contentMapper.selectByPrimaryKey(id);
hashSet.add(tbContent.getCategoryId());
}
//遍历所有的且去重后的id 开始清空redis
for (Long aLong : hashSet) {
redisTemplate.boundHashOps("contentList").delete(aLong);
}
for(Long id:ids){
contentMapper.deleteByPrimaryKey(id);
}
}
@Override
public PageResult findPage(TbContent content, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
TbContentExample example=new TbContentExample();
Criteria criteria = example.createCriteria();
if(content!=null){
if(content.getTitle()!=null && content.getTitle().length()>0){
criteria.andTitleLike("%"+content.getTitle()+"%");
}
if(content.getUrl()!=null && content.getUrl().length()>0){
criteria.andUrlLike("%"+content.getUrl()+"%");
}
if(content.getPic()!=null && content.getPic().length()>0){
criteria.andPicLike("%"+content.getPic()+"%");
}
if(content.getStatus()!=null && content.getStatus().length()>0){
criteria.andStatusLike("%"+content.getStatus()+"%");
}
}
example.setOrderByClause("sort_order");
Page<TbContent> page= (Page<TbContent>)contentMapper.selectByExample(example);
return new PageResult(page.getTotal(), page.getResult());
}
@Override
public List<TbContent> findByCategoryId(Long categoryId) {
List<TbContent> contentList = (List<TbContent>) redisTemplate.boundHashOps("contentList").get(categoryId);
if(contentList==null||contentList.size()==0){
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(categoryId);
criteria.andStatusEqualTo("1");
example.setOrderByClause("sort_order");
contentList = contentMapper.selectByExample(example);
redisTemplate.boundHashOps("contentList").put(categoryId,contentList);
System.out.println("数据库查");
}else{
System.out.println("redis查");
}
return contentList;
}
@Override
public void updateStatus(Long[] ids, String status) {
HashSet<Long> hashSet = new HashSet<>();
//遍历得到所有需要修改的categoryId 去重
for (Long id : ids) {
TbContent tbContent = contentMapper.selectByPrimaryKey(id);
hashSet.add(tbContent.getCategoryId());
}
//遍历所有的且去重后的id 开始清空redis
for (Long aLong : hashSet) {
redisTemplate.boundHashOps("contentList").delete(aLong);
}
for (Long id : ids) {
TbContent content = contentMapper.selectByPrimaryKey(id);
content.setStatus(status);
contentMapper.updateByPrimaryKey(content);
}
}
}