摘要:做商城开发时经常会遇到高并发的问题,除了使用Redis队列等技术外,也可以使用Mysql数据库的“锁”机制。悲观锁:一般使用 select ...for update 对所选择的数据进行加锁处理,例如select * from yzm_order...
做商城开发时经常会遇到高并发的问题,除了使用Redis队列等技术外,也可以使用Mysql数据库的“锁”机制。
一、悲观锁
1、当事务在操作数据时把这部分数据进行锁定,直到操作完毕后再解锁,其他事务操作才可操作该部分数据。这将防止其他进程读取或修改表中的数据。
2、实现:
一般使用 select ...for update 对所选择的数据进行加锁处理,例如 SELECT * FROM `yzm_order` WHERE `order_no` = 'S201909277894' LIMIT 1 FOR UPDATE ,这样就通过开启排他锁的方式实现了悲观锁。此时在 yzm_order 表中,order_no 为 S201909277894 的那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。
二、乐观锁
1、如果有人在你之前更新了,你的更新应当是被拒绝的,可以让用户重新操作。
2、实现:
大多数基于数据版本(Version)记录机制实现,
具体可通过给表加一个版本号或时间戳字段实现,当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断当前版本信息与第一次取出来的版本值大小,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据,拒绝更新,让用户重新操作。
在数据库中,悲观锁的流程如下:
在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。
如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。
如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。
其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。
测试一把:
会话1:
SET autocommit=0 SELECT * FROM yzm_order WHERE `order_no` = 'S201909277894' FOR UPDATE COMMIT
新会话2:
在会话1未commit之前,执行以下SQL,会发生堵塞
UPDATE `yzm_order` SET `status` = 2 WHERE id = 1;
当会话1长时间未提交事务时,会发生以下报错信息
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction
再次测试:
例1: (明确指定主键,并且有此记录,row lock)
SELECT * FROM yzm_order WHERE id='3' FOR UPDATE;
例2: (明确指定主键,且无此记录,无lock)
SELECT * FROM yzm_order WHERE id='-1' FOR UPDATE;
例3: (无主键,table lock)
SELECT * FROM yzm_order WHERE status='1' FOR UPDATE;
例4: (主键不明确,table lock)
SELECT * FROM yzm_order WHERE id<>'3' FOR UPDATE;
例5: (主键不明确,table lock)
SELECT * FROM yzm_order WHERE id LIKE '3' FOR UPDATE;
总结:InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住。
网友评论:
交换链接吗
2019-10-22 09:13:36 回复
网友评论:
交换链接吗
2019-07-29 21:33:14 回复
网友评论:
还有这种东西?
2019-07-29 16:05:30 回复