跳至主要內容

悲观锁、乐观锁

zheng大约 4 分钟数据库mysql

1、悲观锁

假设会发生并发冲突,屏蔽一切可能违反数据完整性的操作(具有强烈的独占和排他性)

       依赖数据库的锁机制实现,以保证操作最大程度的独占性。

 百度百科:正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

2、缺点

数据库性能的大量开销,特别是对长事务而言,这样的开销无法承受

3、实现方法

**Mysql中 :**

在sql后面加上 for update或者for update nowait

for update和for update nowait区别:

     1. for update 锁定当前操作数据,其他事务等待

     2. for update nowait 锁定当前数据,其他事务发现数据被锁定,立即返回"ORA-00054错误,内容是资源正忙, 但指定以 NOWAIT 方式获取资源"

     例如:select * from account where name="123" for update

     优点:无论是在单机还是分布式中,只要使用的是同一个数据库,那么悲观锁就能起到作用。

     缺点:锁定数据后,必将影响其他操作,在大流量的情况下,操作速度变慢

**JAVA中 :**

    独占锁是一种悲观锁,synchronized就是一种独占锁,它假设最坏的情况,并且只有在确保其它线程不会造成干扰的情况下执行,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。

4、使用场景举例

以mysql InnoDB为例

Demo:

   begin;

        select amount from item where item_id = 1 for update;

 // 通过amount来做出一些行为,例如告诉用户库存不足,购买失败,然后只有amount > 1才进入更新库存操作

        update item set amount = amount - 1 where item_id = 1;

        commit;
由于是串行执行,其他事务的for update必须等该当前事务的 for update 语句执行,所以我们不必担心我们获得的amount被修改过,因为它永远是最新的

0、乐观锁:

不是真正的锁,而是一种实现 : 是一种实现的

1、乐观锁:

假设不会发生并发冲突,只有在提交操作时检查是否违反数据完整性,乐观锁不能解决脏读问题

        乐观锁大多都基于数据版本(version)记录机制实现,何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据表增加一个“version”字段来实现。读取出数据时,将此版本一同读出,之后更新时,对此版本后 +1。此时,将提交的版本数据与数据库表对应记录的当前版本信息对比时,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据。

2、优缺点:

    优点 :可以多个事务同时进行,然后根据返回的不同结果做相应的操作,避免了长事务中的数据库加锁开销。

    缺点 :乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户余额更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。

在系统设计阶段,我们应该充分考虑到这些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。

3、步骤 :

	// 1.查询出商品信息
	select (status,status,version) from t_goods where id=#{id}
	// 2.根据商品信息生成订单
	// 3.修改商品
	update t_goods
	set status=2,version=version+1 where id=#{id} and versio{139}};
上次编辑于:
贡献者: 郑天祺