数据库锁:乐观锁和悲观锁,共享锁和排它锁,行级锁和表级锁
博客专区 > vshcxl 的博客 > 博客详情
数据库锁:乐观锁和悲观锁,共享锁和排它锁,行级锁和表级锁
vshcxl 发表于1年前
数据库锁:乐观锁和悲观锁,共享锁和排它锁,行级锁和表级锁
  • 发表于 1年前
  • 阅读 86
  • 收藏 2
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

一、悲观锁和乐观锁

  我们经常在开发中遇到数据库并发处理时,处理不一致的问题。需要对程序做并发控制。
典型的并发时出现的冲突有两种:
1、丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。
例如X=0  A1把X=X+1  A2也设置X=X+1    如果A1和A2同时执行,可能出现最终X=1的情况。而我们需要得到的是X=2  。   这就需要update处理为串行化的。
2、脏读:读到的数据可能是旧的。    初使X=0    A1把X设置为1,A2读取时X是1,但A1后面又修改成了2,或回滚到了0,那么A2读取的数据就是脏数据。
A2读取的是未提交的数据。一般数据库不会设为读未提交,所以一般不会出现脏读。

那什么是乐观锁,什么是悲观锁。

悲观锁:需要使用数据库的锁机制,如数据库有表级排它锁,有行级排它锁。
假定一切操作都可能发现并发冲突,所以采取悲观态度。通过加锁,屏蔽一切可能违反数据完整性的操作
比方select * from table for update;  就是表锁,
select * from table where x = 1 for update; 就是行锁。
当使用for update后,其它会话还是可以执行select操作,但无法执行select xx for update操作,只有当前会话commit后,其它for update操作才会被执行。
典型例子可以参考quartz集群的锁机制:http://blog.itpub.net/11627468/viewspace-1764753/
当然,此时也不可以update,update需要等select xx for update 所在会话commit后才能执行。
注:mysql需要设置autocommit=0

乐观锁:其实不是真实的去锁住记录不让访问,或者不让更新。
假定操作很少发生冲突,一般对于读多写少的情况。只在提交操作时检查是否违反数据完整性。[1] 乐观锁不能解决脏读的问题。
可以通过版本号是否比上个版本号或者时间戳来实现。
对于冲突检测后的处理,需要业务逻辑去处理。

二、排它锁和共享锁
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。
当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。
数据库利用这两种基本的锁类型来对数据库的事务进行并发控制。


三、表级锁和行级锁

     DML锁的目的在于保证并发情况下的数据完整性,主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。
     当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。

值  锁模式  锁描述  SQL
0 NONE 1  NULL  空  SELECT
2  SS(ROW-S)  行级共享锁
其他对象只能查询这些数据行  SELECT FOR UPDATE、LOCK FOR UPDATE、
LOCK ROW SHARE
3  SX(ROW-X)  行级排它锁
在提交前不允许做DML操作  INSERT、UPDATE、DELETE、
LOCK ROW SHARE
4  S(SHARE)  共享锁  CREATE INDEX、LOCK SHARE
5  SSX(S/ROW-X)  共享行级排它锁  LOCK SHARE ROW EXCLUSIVE
6  X(eXclusive)  排它锁  ALTER TABLE、DROP TABLE、DROP INDEX、
TRUNCATE TABLE、LOCK EXCLUSIVE

四、几个问题
1.UPDATE/DELETE操作会将RS锁定,直至操作被COMMIT或者ROLLBACK;
若操作未COMMIT之前其他session对同样的RS做变更操作,则操作会被hold,直至前session的UPDATE/DELETE操作被COMMIT;


2.session内外SELECT的RS范围
前提:INSERT、UPDATE操作未COMMIT之前进行SELECT;
若在同一session内,SELECT出来的RS会包括之前INSERT、UPDATE影响的记录;
若不在同一session内,SELECT出来的RS不会包括未被COMMIT的记录;


3.SELECT.... FOR UPDATE [OF cols] [NOWAIT/WAIT] [SKIP LOCKED]
OF cols:只锁定指定字段所在表的RS,而没有指定的表则不会锁定,只会在多表联合查询时出现;
NOWAIT:语句不会hold,而是直接返回错误ORA-00054: resource busy and acquire with NOWAIT specified;
WAIT N:语句被hold N秒,之后返回错误ORA-30006: resource busy; acquire with WAIT timeout expired;
SKIP LOCKED:不提示错误,而是直接返回no rows selected;
以上几个选项可以联合使用的,比较推荐的有:
SELECT.... FOR UPDATE NOWAIT:对同一RS执行该SQL时,直接返回错误;
SELECT.... FOR UPDATE NOWAIT SKIP LOCKED:对同一RS执行该SQL时,直接返回空行;
PS:当RS被LOCK住之后,只对同样请求LOCK的语句有效,对无需LOCK的SELECT语句并没有任何影响;





以上悲观锁和乐内容参考:
http://www.cnblogs.com/guyufei/archive/2011/01/10/1931632.html
spring锁实现参数:
http://blog.itpub.net/12158104/viewspace-374745
关于隔离级别可以参考:
http://blog.itpub.net/11627468/viewspace-1793036/
关于数据库的锁可以参考:
http://zhidao.baidu.com/link?url=zRnaslJ8INtEviT--BzrT2bMOqf4LJQzL-NQg2ECu6l-s-xPHi11bBlNjN2_zyNrwd9M0ZnbelQntmfYPB0ifq

共有 人打赏支持
粉丝 17
博文 261
码字总数 23603
×
vshcxl
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: