MySQL学习笔记(四)悲观锁 for update

恼骚

最近在搞并发的问题,订单的异步通知和主动查询会存在并发的问题,用到了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';

 执行结果,没有阻塞,则能正常查询出数据,不会受第一个事务的影响

第二次,开启事务,提交事务

异步查询开启事务,提交事务

主动查询加锁则不受影响

总结:锁如果是回滚或者提交事务,会自动释放掉锁的。

下面研究以下行锁和表锁

  

 

猜你喜欢

转载自www.cnblogs.com/tinywan/p/9655664.html