总结Mysql中悲观锁是怎么使用的

  • Post author:
  • Post category:mysql


这俩天看了很多有关高并发电商网站的解决方案。本文主要考虑在实现在与数据服务器交互的部分。乐观锁主要有2种解决方法,version和时间戳,从别的资料中很容易理解。但涉及悲观锁的具体解决方案,一直理解的不够达到实现程度。以下分享一下自己的经验,很多知识材料来自其他博客大佬们的无私分享~


在一般查询sql中,是这样的写查询:

1.select * from table where id=1;
此时并没有提交该事务1

这样做是无法起到上锁的目的,也就是说其他事务中可能有

2.update table set name='wind' where id=1;

事务2如上文修改了数据,并commit

此时事务1执行下一句

3.select * from table where id=1;

发现会发现name字段2次结果不一致,这就是数据库事务并发时可能发生的不可重复读情况

解决方法是

select * from table where id=1 LOCK IN SHARE MODE;

这种写会为事务1该行加上共享锁。

事务2此时想要执行update语句就会阻塞,因为他需要为id=1的那条记录加排它锁,而排它锁是与共享锁无法共存的。


*注:共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。*


Mysql的InnoDB引擎支持事务,其默认事务隔离级别是REPEATABLE _READ


1.READ_UNCOMMITED

这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。

2.READ_COMMITED

保证一个事务修改的数据提交后才能被另外一个事务读取,即另外一个事务不能读取该事务未提交的数据。

3.REPEATABLE _READ

保证一个事务相同条件下前后两次获取的数据是一致的

4.SERIALIZABLE

事务被处理为顺序执行。

通过在一条记录上设共享锁,可以在该事务期间保证2次读取同一记录的结果一致,也保证其他事务不会更改相同记录,这一方法用于在并发事务中保证查询sql的数据一致性。


通常我们在电商并发网站中,会涉及对同一个商品number数的更新,

事务1中这样写,代表了一个用户在服务器在一个数据库连接执行的任务。

begin;

update goods set number=number-1 where good_id=#{id} and number>0;

insert into detail(order_id,good_id ,user_name) values(null,1,”wind”);

commit;

另一个用户在一个数据库连接里需要执行的事务2此时是

begin;

⑴update goods set number=number-1 where good_id=#{id} and number>0;

insert into detail(order_id,good_id ,user_name) values(null,1,”sea”);

commit;

因为他们请求同一个商品也就是说good_id一致,但因为是update语句所以都需要上为该记录上排他锁,此时如果事务1执行过程中,事务2虽然是并发执行,但事务2会阻塞在⑴这句,等事务1commit后,释放行锁,事务2才会成功加排它锁继续执行。这样实现了并发事务在对同一记录的访问中,保证安全,不会超买。

突然思路没了…这是我的一些理解,希望能对大家有所帮助。



版权声明:本文为windneverstop原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。