乐观锁和悲观锁

首先我们必须明白:

乐观锁和悲观锁是数据库操作的两种安全实现的方式,各有优劣,谁好谁坏要具体结合实际场景分析!

 

什么是乐观锁?

乐观锁总是乐观的认为:我们在数据库操作的过程中,操作的数据库数据不会被其他人修改,所以不上锁,但是在最后更新之前会检查这条数据是否为之前的数据。

 

什么是悲观锁?

悲观锁总是悲观的认为:在我们对数据库进行操作的过程中,会有人来修改我们的数据,所以每次拿完数据,都要给表或者列上锁。

 

场景比较:

1、经常查找,却很少更新操作的表(多读少写的场景)

乐观锁要优于悲观锁。

因为悲观锁每次查完数据库数据,都要锁住数据,直到自己操作结束才释放。这个过程中,其他要操作此数据的线程都会处于阻塞等待状态。在多读少写的场景中,大多数线程只是读取数据,而没有更新数据,所以不上锁的乐观锁支持多线程同时操作,具有更大的优势。

2、经常更新、删除操作的表(多写场景)

悲观锁要优于乐观锁。

因为乐观锁每次查完数据都不上锁,多写场景容易造成多人同时操作同一条数据的情况,当其中一人先完成操作,其他人只能回滚重新执行了,这样就造成了很多的无用功。而使用悲观锁,只能一个一个排着队去更新操作,虽然效率低了,但不会造成无用功操作,增加服务器压力。

 

实现方式:

乐观锁:

①、在数据库表中加上一个版本号字段(version)

②、每次读取自己要操作的数据时,一同读取保存version字段值

③、更新操作前,再从数据库表中的对应version字段值,与之前保存的version作比较,相等可以进行更新,不等就回滚重新来过。

④、更新时,一同让 version+1,表示数据已被修改过。

 

什么是乐观锁的ABA问题?

乐观锁机制存在一个问题:一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。

关于ABA问题,只要我们严格遵循“每次更新完数据之后对version+1”操作,就可以规避了。

 

悲观锁:

在数据查询的时候,加上 for update。

具体步骤:

①、开启事务

begin; / begin work; / start transaction; (三者选一即可)

②、查询某表数据(id为主键)

select * from 表名 where id = 1 for update

③、修改表数据

update 表名 set 表字段 = xxx;

④、提交事务

commit; / commit work; (二选一即可)

 

关于for update的注意事项:

1、如果不开启事务,for update是不会锁任何东西的。

2、开启事务后,where条件字段是索引字段的话,该锁为行锁,如果不是索引字段,则为表锁。

3、for update 是写锁,该操作不会影响读操作。

 

关于悲观锁的困惑过我的问题解释:

1、mysql使用事务前,需要关闭自动提交(set autocommit=0;)吗?

答:不需要!mysql 使用事务功能是不需要手动关闭自动提交的,只要你 begin 开启了事务,自动提交就会被自动关闭,然后在使用 commit 之后,又会被重新打开。

2、网上怎么有人说 for update 会锁住读操作?

答:正常的读操作是不会受到影响的!当我执行 select * from 表名 where id=1 for update;后,在另外的事务中如果再次执行select * from 表名 where id=1 for update;则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态。如果我是在第二个事务中执行select * from 表名 where id=1;则能正常查询出数据,不会受第一个事务的影响。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值