恼骚
最近在搞并发的问题,订单的异步通知和主动查询会存在并发的问题,用到了Mysql数据库的 for update 锁
在TP5直接通过lock(true),用于数据库的锁机制
Db::name(‘pay_order‘)->where(‘order_no‘,‘S1807081342018949’)->lock(true)->find();
打印生成的SQL语句
SELECT * FROM `pay_order` WHERE `order_no` = ‘S1807081342018949‘ LIMIT 1 FOR UPDATE
for update 是什么?
以下这句话应用来自:http://www.cnblogs.com/bigfish--/archive/2012/02/18/2356886.html
在oracle中,利用 select * for update 可以锁表。假设有个表单products ,里面有id跟name二个栏位,id是主键。
例1: (明确指定主键,并且有此笔资料,row lock)
SELECT * FROM products WHERE id=‘3‘ FOR UPDATE;
例2: (明确指定主键,若查无此笔资料,无lock)
SELECT * FROM products WHERE id=‘-1‘ FOR UPDATE;
例3: (无主键,table lock)
SELECT * FROM products WHERE name=‘Mouse‘ FOR UPDATE;
例4: (主键不明确,table lock)
SELECT * FROM products WHERE id<>‘3‘ FOR UPDATE;
例5: (主键不明确,table lock)
SELECT * FROM products WHERE id LIKE ‘3‘ FOR UPDATE;
注1: FOR UPDATE仅适用于InnoDB,且必须在交易区块(BEGIN/COMMIT)中才能生效。
注2: 要测试锁定的状况,可以利用MySQL的Command Mode ,开二个视窗来做测试。(点开链接,这里已经有人做个测试了)
先开始一把
使用悲观锁的原理就是,当我们在查询出 pay_order 信息后就把当前的数据锁定,直到我们修改完毕后再解锁。那么在这个过程中,因为 pay_order 被锁定了,就不会出现其他操作者来对其进行修改了。
第一次,开启事务,但是不提交事务
异步通知
-- 开启事务 START TRANSACTION; -- 查询订单 SELECT id,order_no,`status` FROM `pay_order` WHERE `order_no` = ‘S1807081342018949‘ LIMIT 1 FOR UPDATE; -- 修改订单 UPDATE `pay_order` SET `status` = 11 WHERE id = 347; COMMIT; -- 查询数据是否修改成功 SELECT id,order_no,`status` FROM `pay_order` WHERE `order_no` = ‘S1807081342018949‘ LIMIT 1 FOR UPDATE;
执行结果:很快就执行完毕了,但是数据并没有修改成功(注意:但是重复执行一次,则数据又修改成功了)
主动查询
1、加锁
SELECT id,order_no,`status` FROM `pay_order` WHERE `order_no` = ‘S1807081342018949‘ LIMIT 1 FOR UPDATE;
执行结果,一直在阻塞中
过一会,会自动取消锁机制
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction
2、不加锁
SELECT id,order_no,`status` FROM `pay_order` WHERE `order_no` = ‘S1807081342018949‘;
执行结果,没有阻塞,则能正常查询出数据,不会受第一个事务的影响
第二次,开启事务,提交事务
异步查询开启事务,提交事务
主动查询加锁则不受影响
总结:锁如果是回滚或者提交事务,会自动释放掉锁的。
下面研究以下行锁和表锁
例1: 明确指定主键,并且有此数据,row lock
show variables like ‘%storage_engine%‘;
原文:https://www.cnblogs.com/tinywan/p/9655664.html