(1)作为缓存。
1.搭建一个springboot+mp的工程
2.引入redis相关的依赖
3.配置redis
4.service代码
package com.wyj.service; import com.ykq.dao.DeptDao; import com.ykq.entity.Dept; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class DeptService { @Resource private DeptDao deptDao; @Autowired private RedisTemplate redisTemplate; public Dept findById(Integer deptId){ //1.从缓存中查询该数据 Object o = redisTemplate.opsForValue().get("findById::" + deptId); if(o!=null){//表示从缓存中获取该数据 return (Dept) o; } Dept dept = deptDao.selectById(deptId); redisTemplate.opsForValue().set("findById::"+deptId,dept);//把查询的结果放入缓存 return dept; } //数据库和缓存同步问题! public int delete(Integer deptId){ redisTemplate.delete("findById::"+deptId);//删除缓存 int i = deptDao.deleteById(deptId); return i; } public int update(Dept dept){ redisTemplate.delete("findById::"+dept.getDeptId());//删除缓存 int i = deptDao.updateById(dept); redisTemplate.opsForValue().set("findById::"+dept.getDeptId(),dept); return i; } }
基于spring的缓存注解。
package com.wyj; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @MapperScan(basePackages = "com.ykq.dao") @EnableCaching //开启缓存的注解 public class SpringbootRedis02Application { public static void main(String[] args) { SpringApplication.run(SpringbootRedis02Application.class, args); } } package com.wyj.service; import com.wyj.dao.DeptDao; import com.wyj.entity.Dept; 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.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class DeptService { @Resource private DeptDao deptDao; //该注解作用:会先查询缓存,如果缓存存在,则不会执行代码块。 如果缓存中不存在则执行该方法,并把该方法的返回值存放到redis中 @Cacheable(cacheNames = "findById",key = "#deptId") //缓存的key值 为findById public Dept findById(Integer deptId){ System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); Dept dept = deptDao.selectById(deptId); return dept; } //数据库和缓存同步问题! // beforeInvocation:是否在方法执行前就清空,缺省为 false, // 如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。 @CacheEvict(cacheNames = "findById",key = "#deptId") public int delete(Integer deptId){ int i = deptDao.deleteById(deptId); return i; } //这个注解是必须执行方法体,而且会把方法体执行的结果放入到缓存中。 如果发生异常则不操作缓存。 @CachePut(cacheNames = "findById",key = "#dept.deptId") public Dept update(Dept dept){ int i = deptDao.updateById(dept); return dept; } }
(2)作为分布式锁
package com.wyj.distributedlock.service; import com.wyj.distributedlock.dao.StockDao; import com.wyj.distributedlock.entity.Stock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; @Service public class StockService { @Resource private StockDao stockDao; @Autowired private StringRedisTemplate redisTemplate; public String decrStock(Integer productId) {//synchronized () 同步方法 同步代码块 Boolean flag = redisTemplate.opsForValue().setIfAbsent("product::" + productId, "ykq",30, TimeUnit.SECONDS); //查询对应的id的库存 if(flag) {//获取锁了 try { Stock stock = stockDao.selectById(productId); if (stock.getNum() > 0) { //根据id修改库存 stock.setNum(stock.getNum() - 1); stockDao.updateById(stock); //异常发生 // int c=10/0; System.out.println("库存剩余:" + (stock.getNum())); return "库存减少成功"; } else { return "库存不足"; } }catch (Exception e){ throw new RuntimeException(e.getMessage()); } finally { redisTemplate.delete("product::" + productId);//释放锁资源 一定再finally } }else{ System.out.println("服务器正忙请稍后再试.........."); return "服务器正忙请稍后再试.........."; } } }
使用第三方组件redisson-----专门用于解决分布式问题。
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.13.4</version> </dependency>
@Bean public RedissonClient getRedisson(){ Config config=new Config(); config.useSingleServer().setAddress("redis://192.168.213.188:6379"); RedissonClient redissonClient = Redisson.create(config); return redissonClient; }
package com.wyj.distributedlock.service; import com.wyj.distributedlock.dao.StockDao; import com.wyj.distributedlock.entity.Stock; import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.concurrent.TimeUnit; @Service public class StockService { @Resource private StockDao stockDao; @Autowired private RedissonClient redisson; public String decrStock(Integer productId) {//synchronized () 同步方法 同步代码块 RLock lock = redisson.getLock("product::" + productId);//获取锁对象 try { lock.tryLock(60,20,TimeUnit.SECONDS); //自己别设置时间。 Stock stock = stockDao.selectById(productId); if (stock.getNum() > 0) { //根据id修改库存 stock.setNum(stock.getNum() - 1); stockDao.updateById(stock); //异常发生 // int c=10/0; // Thread.sleep(35000); System.out.println("库存剩余:" + (stock.getNum())); return "库存减少成功"; } else { return "库存不足"; } }catch (Exception e){ throw new RuntimeException(e.getMessage()); } finally { lock.unlock(); } } }
(3)作为点赞量videaId,0 incr(videaId),排行榜,转发量。
什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景 。 关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助redis的SortedSet进行热点数据的排序。 在奶茶活动中,我们需要展示各个部门的点赞排行榜, 所以我针对每个部门做了一个SortedSet,然后以用户的openid作为上面的username,以用户的点赞数作为上面的score, 然后针对每个用户做一个hash, 通过zrangebyscore就可以按照点赞数获取排行榜,然后再根据username获取用户的hash信息,这个当时在实际运用中性能体验也蛮不错的。
(4)限时业务的运用
redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。