如何利用Redis事务解决超售

怎么预防数据库超售?

第一种办法技术上最稳妥,但是业务上不可行。那就是设置事物的隔离级别为Serializable。这个事物隔离级别非常严格,因为多个事物并发执行,对同一条记录修改,就会出现超售现象。所以干脆,咱们就禁止事物的并发执行吧。Serializable就是让数据库,串行执行事物,一个事物执行完,才能执行下一个事物,这种办法确实解决了超售的问题。但是同学们,SQL语句对数据的修改,最终都是要反应到磁盘上的。磁盘的IO速度你也是知道的,比内存和CPU慢多了。所以说,串行化执行事物,一个事物执行的时间就不短,你让后面的排队的事物等到什么时候?因此说,串行化执行事物的办法是不可行的。你要是这么搞,电商系统几千万人一起买东西的时候,几千万个事物串行执行,最后的事物,真得是要等到猴年马月了,所以绝对不能这么搞。

image

第二种办法是给数据表设置乐观锁。我们在数据表上面添加一个乐观锁字段,数据类型是整数的,用来记录数据更新的版本号,这个跟SVN机制很像。乐观锁是一种逻辑锁,他是通过版本号来判定有没有更新冲突出现。比如说,现在A商品的乐观锁版本号是0,现在有事务1来抢购商品了。事务1记录下版本号是0,等到执行修改库存的时候,就把乐观锁的版本号设置成1。但是事务1在执行的过程中,还没来得及执行UPDATE语句修改库存。这个时候事务2进来了,他执行的很快,直接把库存修改成99,然后把版本号变成了1。这时候,事务1开始执行UPDATE语句,但是发现乐观锁的版本号变成了1,这说明,肯定有人抢在事务1之前,更改了库存,所以事务1就不能更新,否则就会出现超售现象。

image

你看,这就是乐观锁的机制了。它允许多个事物并发执行,只需要编写Java程序,或者Python程序什么的,每次更新都去比较一下乐观锁字段的版本号,就能实现乐观锁的功能了。这个机制还是挺不错的,保证了业务的并发性。那么有的同学可能会说,老师,是不是我们要给每个表都添加上乐观锁呢?我觉得只要有并发修改,只要是多个事物同事修改记录,就会出现类似超售的现象。确实,如果不加乐观锁。即便不是秒杀促销,只要是正常的商品销售,多个事物同时修改库存,就会出现超售现象,只不过秒杀业务放大了超售现象的结果,让它变得更加严重。

Redis的事务机制避免超售

Redis的事物跟MySQL的事物完全不是一回事儿,Redis的事物就是个批处理机制,底层的原理和乐观锁类似,只不过把乐观锁拿到内存中来实现。下面我来详细说明一下Redis的事物机制。

比如说现在客户端A,在修改数据之前,首先要观察要修改的数据,相当于记下了数据的版本号。然后我们可以开启事务机制,于是所有的命令都不会立即发送给Redis,而是先缓存到客户端本地。等我们提交事物的时候,一次性,把这个命令发送给Redis。Redis分析版本号之后,发现没有问题,这时候就会执行这些批处理的命令,而且在执行过程中不允许打断,不会处理其他客户端的命令,这样就不会出现超售现象。

image

有一种情况,客户端A的事物提交会失败。那就是,在客户端A在本地缓存命令的时候,这个时候客户端B修改了数据,版本号同时也更新了。这个时候客户端A提交事物,Redis发现客户端A的版本号,跟现有的数据版本号有逻辑冲突,所以就禁止执行客户端A的命令,这样事物就失败了。失败归失败,但是没有产生超售的现象。

Redis的AOF模式

由于Redis使用内存缓存数据,如果Redis宕机,重启Redis之后,原本内存中缓存的数据就全都消失了。为了在宕机之后能有效恢复之前缓存的数据,我们可以开启Redis的持久化功能。

Redis有RDB和AOF两种持久化方式。RDB会根据指定的规则定时将内存中的数据保存到硬盘中,容易因为持久化不及时,导致恢复的时候丢失一部分缓存数据。AOF会将每次执行的命令及时保存到硬盘中,实时性更好,丢失的数据更少,所以本课程中我们选择AOF模式。

修改Redis配置文件,把原本的save注释掉,然后添加上新的save设置。在结尾还要追加两句话,然后重新启动Redis容器。

bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
logfile ""
databases 12
#关闭RDB
save ""
#save 900 1
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
requirepass abc123456
#配置AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync always
posted @ 2026-01-13 15:20  hwq1992  阅读(0)  评论(1)    收藏  举报