什么是脏数据缓存中是否可能产⽣脏数据,如果出现脏数据该
怎么处理?
(1)背景介绍:
脏数据:从⽬标中取出的数据已经过期、错误或者没有意义,这种数据就叫做脏数据。
脏读:读取出来脏数据就叫脏读。
(2)知识剖析:
1、数据库中的并发事务处理问题:
脏读:在并发访问的情况下,不同的事务对相同的数据进⾏操作,在事务A修改数据还未提交的时候,事务B对该数据进⾏读取,读出了事物A修改过后的数据,但是事物A最终没有提交,这种情况就是数据库中的脏读情况
更新丢失:对于同⼀⾏数据不同事务进⾏更新,结果覆盖
幻读:事务A前后两次读取,后⼀次读取的数据变多了,事物B在两次读取中间已经进⾏数据插⼊
不可重复读:事务A读取了事务B修改前后的两次数据,不符合隔离型
隔离等级:可以解决上述问题,mysql默认可重复读的隔离等级,只会存在读取的数据和数据库不⼀致的问题
2、mybati⼀级缓存中的脏数据:
mybatis的⼀级缓存:默认是SqlSession级别,只要通过session查过的数据,都会放在session上,下⼀次再查询相同id的数据,都直接冲缓存中取出来,⽽不⽤到数据库⾥去取了。
mybatis⼀级缓存脏数据:当有不同的sqlSession在对数据库进⾏操作,⼀级缓存只能保证当前sqlSession中的增删改在⼀级缓存中⾃动更新,就会产⽣脏数据。
3、mybati⼆级缓存中的脏数据:
mybatis⼆级缓存:是SessionFactory级别,和namespace绑定,同⼀个namespace放到⼀个缓存对象中,当这个namaspace中执⾏了⾮sselect语句的时候,整个namespace中的缓存全部清除掉。
mybatis⼆级缓存脏数据:引起脏读的操作通常发⽣在多表关联操作中,⽐如在两个不同的mapper中都涉及到同⼀个表的增删改查操作,当其中⼀个mapper对这张表进⾏查询操作,此时另⼀个mapper进⾏
了更新操作刷新缓存,然后第⼀个mapper⼜查询了⼀次,那么这次查询出的数据是脏数据。出现脏读的原因是他们的操作的缓存并不是同⼀个。
所以不推荐使⽤mybatis的⾃带⼀⼆级缓存,推荐使⽤第三⽅缓存:memcached或者redis。
(3)常见问题:
redis中怎么更新缓存避免脏读?
(4)解决⽅案:
读写部分:
if(redis存在数据){
读取redis数据
}else{
数据库读取,同时存redis+设置超时时间
更新部分:
if(数据库update){
江歌案是怎么发生的更新redis+设置超时时间
(5)编码实战:
演⽰读写部分和更新部分
(6)拓展思考:
还有哪些其他⽅式进⾏redis数据更新
1、主动更新:后台点击更新缓存按钮,从DB查最新数据集合,删除原缓存数据,存储新数据到缓存(或者⽤定时任务来做)
问题:更新过程中删除掉缓存后刚好有业务在查询,那么这个时候返回的数据会是空,会影响⽤户体验,如果⾼并发穿透DB,可能导致服务器崩溃
2、由⽤户触发更新:前台获取数据时发现没有缓存数据就会去数据库同步数据到缓存
问题:当并发请求获取缓存数据不存在的时候,就会产⽣并发的查询数据的操作
3、提前加载好数据:后台点击更新缓存按钮,从DB查最新数据集合,这⾥不删除缓存,通过遍历数据覆盖和删除掉⽆效的数据
问题:逻辑相对⿇烦,⽽且更新机制⽆法通⽤
(7)参考⽂献:
百度⾕歌
(8)更多讨论:
Q1:数据库脏数据和redis脏数据的区别?
A1:数据库脏数据是⽤户对数据进⾏操作存储,存储的数据和实际不符合,redis脏数据是相对于数据库数据⽽⾔的,redis的数据和数据库中数据不⼀致就会导致脏数据
Q2:⽂中代码实战中的redis更新⽅式有什么缺点?
A2:缺点:增加的判断的⽅法,效率偏低,当并发量⾼时,效率影响会更⼤
Q3:主动更新⽅式进⾏redis更新怎么实现?
A3:在后台管理中,设置⼀个按钮,更新redis的操作,⼀般在晚上⽤户访问量少的时候,数据从数据库中查出后放⼊redis