MySQL数据库与Redis缓存数据一致性问题

我们时常接受失望,这样我们才能不断重整旗鼓。——《岛上书店》

1、引言

在最近项目开发中,采用mysql存储持久化数据,redis缓存热门数据,遇到一个问题,对于一些强实时性业务,我们需要先将数据写到mysql上,mysql写入成功后,再去更新redis,从而确保redis解决读的问题,同时保证了关键数据的一致性问题。

但是这里出现了一个问题,如果mysql操作成功了,但是redis出现异常,操作失败,如何实现回滚?

2、MySQL操作成功之后Redis操作失败的回滚

针对Redis出现异常,操作失败,对MySQL进行回滚操作:

传统通过注解@Transactional只会回滚MySQL异常的情况,Redis本身也不具备回滚功能,Redis的事务也只能保证操作顺序一致,并不能保证操作失败进行数据回滚,在MySQL操作成功的情况下,@Transactional注解会认为方法并没有异常,会继续执行而不回滚,这样就导致了MySQL和Redis不一致的情况。

为了避免这种情况,每次操作Redis之后,都会判断Redis有没有操作成功,操作失败则进行手动回滚,加一行代码:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 配合@Transactional注解即可解决问题。

3、一致性问题解决

(1)针对业务进行处理

针对某些对数据一致性要求不是特别高的情况下,可以将这些数据放入Redis,首先查询Redis,例如近期回复、历史排名这种实时性不强的业务。而针对那些强实时性的业务,例如物品购买件数等,则直接写入MySQL上,等到MySQL上写入成功,再同步更新到Redis上去。这样既可以起到Redis的分流大量读请求的作用,又保证了关键数据的一致性。

(2)高并发情况下定时处理

党写入请求较多时,如点赞等操作,则直接写入Redis中去,然后一段时间周期,批量将所有的写入请求从redis中刷新到MySQL中去;如果此时写入请求不多,则可以在每次写入Redis,比如关注操作,都立刻将该命令同步至MySQL中去。这两种方法有利有弊,需要根据实际的业务场景来权衡。

猜你喜欢

转载自blog.csdn.net/zhoutaochun/article/details/81333948