做网站下载哪个软件seox
热点数据缓存:
为了把一些经常访问的数据,放入缓存中以减少对数据库的访问频率。从而减少数据库的压力,提高程序的性能。【内存中存储】成为缓存;
![]()
缓存适合存放的数据:
查询频率高且修改频率低
数据安全性低
作为缓存的组件:
redis组件
memory组件
ehcache组件
等
Redis实现缓存功能
涉及的内容:
spring缓存组件
Redis数据库
AOP面向切面编程
实现:
Spirng缓存组件
//开启缓存注解 @EnableCaching public class CalassNameApplication {public static void main (String[] arge) {SpringApplication.run(CalssNameApplication.class,args);} }添加注解
@Bean public CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();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);// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化.disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager; }实现缓存功能
//所在的类和注入 @Service public class ClazzServiceImpl implements ClazzService { @Autowiredprivate ClazzDao clazzDao;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;查询
查询缓存中是否存在名称为cacheNames::key的值
如果存在则方法不会执行
如果不存在则执行方法体并把方法的返回结果放入缓存cacheNames::key
//Cacheable:表示查询时使用的注解。 //cacheNames:缓存的名称 //key:缓存的唯一表示值 @Cacheable(cacheNames ={ "clazz"}, key = "#id") @Override public Clazz getById(Integer id) {//查询数据库Clazz clazz = clazzDao.selectById(id);return clazz; }修改
先执行方法体
把方法的返回结果放入缓存中
//CachePut:表示修改时使用的注解. //cacheNames:缓存的名称 //key:缓存的唯一表示值 @CachePut(cacheNames = "clazz", key = "#clazz.cid") public Clazz update(Clazz clazz) {//修改数据库int i = clazzDao.updateById(clazz);return clazz; }删除
先执行方法体
把缓存中名称为cacheNames::key的值删除
//CacheEvict:表示删除时使用的注解 //cacheNames:缓存的名称 //key:缓存的唯一表示值 @CacheEvict(cacheNames = "clazz", key = "#cid") @Override public int delete(Integer cid) {int i = clazzDao.deleteById(cid);return i; }原理:
@Service public class ClazzServiceImpl implements ClazzService { @Autowiredprivate ClazzDao clazzDao;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic Clazz getById(Integer id) {//1.查询redis缓存是否命中ValueOperations<String, Object> forValue = redisTemplate.opsForValue();Object o = forValue.get("clazz::" + id);//表示缓存命中if(o!=null){return (Clazz) o;}//查询数据库Clazz clazz = clazzDao.selectById(id);if(clazz!=null){forValue.set("clazz::" + id,clazz);}return clazz;} @Overridepublic Clazz save(Clazz clazz) {int insert = clazzDao.insert(clazz);return clazz;} @Overridepublic Clazz update(Clazz clazz) {//修改数据库int i = clazzDao.updateById(clazz);if(i>0){//修改缓存redisTemplate.opsForValue().set("clazz::"+clazz.getCid(),clazz);}return clazz;} @Overridepublic int delete(Integer cid) {int i = clazzDao.deleteById(cid);if(i>0){//删除缓存redisTemplate.delete("clazz::"+cid);}return i;} }
分布式锁:
自理解:
分布式:
一个网站部署多台服务器
锁:
保证线程安全(将并行改为串行)只允许同时只有一个可以访问;
分布式锁:
通过共享的锁保证每台服务器都能共享到同一个实时数据(进行操作);![]()
涉及内容:
syn和lock锁
nginx代理群
Redis数据库
看门狗redisson
使用工具:
Jmeter压测工具
nginx代理
Jmeter:
模拟高并发工具
使用:
![]()
![]()
![]()
分布式锁实现:
@Service public class StockService { @Autowiredprivate StockDao stockDao;@Autowiredprivate RedissonClient redisson; //public String decrement(Integer productid) {RLock lock = redisson.getLock("product::" + productid);lock.lock();try {//根据id查询商品的库存: 提前预热到redis缓存中int num = stockDao.findById(productid);if (num > 0) {//修改库存---incr---定时器[redis 数据库同步]stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}finally {lock.unlock();}} }原理:
加入syn和lock锁;
syn和lock虽然解决了并发问题,但是项目部署时可能要部署集群模式。
public String decrement(Integer productid) {//根据id查询商品的库存int num = stockDao.findById(productid);synchronized (this) { if (num > 0) {//修改库存stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}}
nginx集群部署并使用redis解决分布式锁文件;
![]()
![]()
![]()
打开并使用nginx代理集群exe文件;
nginx(详细操作见linux笔记内):
代理集群使用
![]()
![]()
配置文件:nginx/conf/nginx.conf
@Service public class StockService { @Autowiredprivate StockDao stockDao;@Autowiredprivate StringRedisTemplate redisTemplate;//public String decrement(Integer productid) {ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();//1.获取共享锁资源Boolean flag = opsForValue.setIfAbsent("product::" + productid, "1111", 30, TimeUnit.SECONDS);//表示获取锁成功if(flag) {try {//根据id查询商品的库存int num = stockDao.findById(productid);if (num > 0) {//修改库存stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}finally {//释放锁资源redisTemplate.delete("product::"+productid);}}else{//休眠100毫秒 在继续抢锁try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return decrement(productid);}} }
redis超时问题[业务代码执行时间超过了上锁时间]
使用第三方redisson插件
<!--引入redisson依赖,看门狗--> <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.24.3</version> </dependency>//配置文件 @Configuration public class RedissonConfig { @Beanpublic RedissonClient redisson(){Config config = new Config(); // //连接的为redis集群 // config.useClusterServers() // // use "rediss://" for SSL connection // .addNodeAddress("redis://127.0.0.1:7181","","","") // ;//连接单机config.useSingleServer().setAddress("redis://172.16.7.18:6379");RedissonClient redisson = Redisson.create(config);return redisson;} }代码实现:
@Service public class StockService { @Autowiredprivate StockDao stockDao;@Autowiredprivate RedissonClient redisson; //public String decrement(Integer productid) {RLock lock = redisson.getLock("product::" + productid);lock.lock();try {//根据id查询商品的库存: 提前预热到redis缓存中int num = stockDao.findById(productid);if (num > 0) {//修改库存---incr---定时器[redis 数据库同步]stockDao.update(productid);System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";} else {System.out.println("商品编号为:" + productid + "的商品库存不足。");return "商品编号为:" + productid + "的商品库存不足。";}}finally {lock.unlock();}} }
问题集:
使用StringRedisTemplate调用get方法获取map数据,使用String接出现
org.springframework.data.redis.RedisSystemException:Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: WRONGTYPE Operation against a key holding the wrong kind of value
DefaultSerializer需要一个可序列化的有效负载,但接收到一个类型的对象
java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.day51.entity.MyEntity]
缓存安全:
什么是缓存穿透以及如何解决?
缓存穿透: 查询的数据在数据库中不存在缓存中也不存在,这时有人恶意访问这种数据,请求到达数据库。
解决方案 :
第一步:在controller层校验数据。对一些不合法的数据过滤掉.
第二步: 使用bloom布隆过滤器。
第三步: 存放一个空对象,并且设置过期时间不能超过5分钟。
什么是缓存击穿以及如何解决?
缓存击穿: 数据库中存在,但是缓存中该数据过期了。这是有大量的请求访问该过期的数据。压力顶到数据库。
解决方案: [1]使用互斥锁 [2]设置永不过期。
什么是缓存雪崩以及如何解决?
缓存雪崩: 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
解决方案: [1] 设置散列的过期时间。 [2]预热数据 [3]搭建redis集群