大家可能都有这样一种感觉,Web程序在本地调试的时候一切正常,放到线上也基本是正常,但是偶尔会有数据错误的情况,这种情况在订单系统中特别常见,因为大部分的订单状态更新都是有两个路径(浏览器跳转和支付服务器的异步推送消息),当然,最终数据要以异步结果为准,但是问题是,浏览器跳转也需要更新订单状态,当这两种方式在很短的时间内同时到达数据库时(一般在一秒内),如果数据库没有加锁,那这个订单会被处理两次。
说到建立数据表时,涉及到支付的,都要用InnoDB引擎,该引擎支持行锁,支持事务,外键。
文章开始的解决办法就是采用InnoDB对要操作的数据行进行锁定。
数据表结构
订单ID(主键) | 订单金额 | 订单状态 |
这里为了简单就只设置了几个核心字段,接下来通过两方面来更新订单。
-
浏览器的跳转
- BEGIN;
- SELECT * FROM `orders` WHERE `order_id`=100 FOR UPDATE;
- //业务逻辑
- COMMIT;
核心语句就三条,一条条来解释
1.BEGIN 手动开启事务(行锁只对开启事务的查询起作用)
2.FOR UPDATE 独占写(成功获得锁后,只有当前进程能够更新该纪录,其他进程如果需要更新该记录,则需进行“锁等待”)
3.COMMIT 提交处理
2. 支付服务器异步推送
处理方式跟浏览器的一样,只要加了行锁就没问题。
这样不管多大的并发过来,因为有了行锁,不会出现问题。