【数据库】乐观锁与悲观锁

锁有两种机制:悲观锁和乐观锁

悲观锁:锁如其名,它是世界观就是悲观的,它认为别人访问正在改变的数据的概率是很高的,所以从数据开始更改时就将数据锁住,直到更改完成才释放。

一个典型的依赖数据库的悲观锁调用:
                  select * from account where name = "Erica" for update
这条SQL语句锁定了account表中所有符合检索条件(name = "Erica")的记录。本次事务提交之前(事务提交时会释放事务过程中的锁) 外界无法修改这些记录。该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止。需要注意的是,select... for update要放到MySQL事务中,即begin和commit中,否则不起作用。

悲观锁可能会造成加锁的时间很长,并发性不好,特别是长事务,影响系统的整体性能。

悲观锁的实现方式:

悲观锁,也是基于数据库的锁机制实现。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

 

乐观锁:锁如其名,它对世界比较乐观,它认为别人访问正在改变的数据的概率是很低的,所以直到修改完成准备提交所做的修改到数据库的时候才会将数据锁住,当你读取以及改变该对象时并不加锁,完成更改后释放。乐观锁不能解决脏读的问题。

乐观锁加锁的时间要比悲观锁短,大大提升了高并发量下的系统整体性能表现。

乐观锁的实现方式:

一、大多数是基于数据版本(Version)记录机制实现,需要为每一行数据增加一个版本标识(也就是每一行数据多一个字段version),每次更新数据都要更新对应的版本号+1。

工作原理:读出数据时,将版本号一同读出,之后更新时,对应此版本号加一。此时,将提交数据的版本信息与数据库表对应记录的当前版本信息进行比较,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据,不得不重新读取该对象并作出更改。

假设数据库账户信息表中有一个version字段,当前值为1;而当前账户余额字段balance为$100.

  1. 操作员A此时将其读出 version = 1,并从其账户余额中扣除$50($100 - $50)
  2. 在操作员A操作的过程中,操作员B也读入此用户信息version = 1,并从其账户余额中扣除$20($100 - $20)
  3. 操作员A完成了修改工作,将数据版本号+1 version = 2,连同账户扣除余额 balance = $50,提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录version更新为2
  4. 操作员B完成了操作,但此时比对数据库记录版本时发现,操作员B提交的数据版本号为2,数据库记录当前版本也为2,不满足“提交版本必须大于记录当前版本才能执行更新”的乐观锁策略”,因此,操作员B的提交被驳回。这样就避免了操作员B用基于version = 1的旧数据修改的结果覆盖操作员A的操作结果的可能。

从上面的例子可以看出,乐观锁机制避免了长事务中的数据库加锁开销(操作员A和操作员B操作过程中,都没有对数据库数据加锁),大大提升了高并发量下的系统整体性能表现。

二、使用时间戳来实现

同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp),和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

 

悲观锁和乐观锁的适用场景

如果并发量不大,可以使用悲观锁解决并发问题;但如果系统的并发量非常大的话,悲观锁会带来非常大的性能问题,所以我们就需要选择乐观锁。现在大部分应用都应该是乐观锁的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值