`
yuan_xulong
  • 浏览: 87890 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

数据库隔离机制、锁学习笔记

阅读更多

    长久以来,对数据库的各种隔离机制一直很模糊,总搞不清楚在别人眼里很简单的锁机制,事务隔离机制,最近查了一些资料,把自己对数据库的一些理解写下来,权当笔记,不对的地方希望大家指正。

为了确保并发用户在存取同一数据库对象时的正确性(即无丢失修改、可重复读、不读“脏”数据),数据库中引入了锁机制:

  从数据库角度来说,数据库一般情况下会有以下两种锁类型:

  1.排它锁X锁):若事务T对数据D加X锁,则其它任何事务都不能再对D加任何类型的锁,直至T 释放D 上的X 锁;一般要求在修改数据前要向该数据加排它锁,所以排它锁又称为写锁,被写锁锁定的记录可以被无锁读取,比如在oracle中没有读锁的概念,在sqlserver中可以使用with nolock。

  2.共享锁S锁):若事务T对数据D加S 锁,则其它事务只能对D加 S锁,而不能加X 锁,直至 T 释放D 上的S 锁;一般要求在读取数据前要向该数据加共享锁,所以共享锁又称为读锁

说明:因为任务事务在读取或者更改一条数据之前,都需要先申请相应的锁类型,所以一旦加上写锁,则其它事务只能等待该事务完成后才能申请相应的锁。一旦加上读锁(共享锁),则别的事务还可以对相同的数据申请共享锁,可以对数据进行读取,则不能修改,无锁读取在sqlserver 中可以使用select ...from ....with nolock。在oracle没有读锁概念。

其它锁概念:

悲观锁:指对于外界对数据的修改持保守态度,为了保持数据被操作的一致性,于是对数据采取了数据库层次的锁定状态,依靠数据库提供的锁机制来实现。该锁只是基于以上数据库提供的锁实现。

乐观锁:与“悲观锁”正好相反,该锁机制认为数据资料的存取很少发生冲突,采取了宽松的锁机制,一般情况下,乐观锁由开发者自行实现,一般情况下,开发者为数据库需要乐观锁的表增加一个版本字段或者时间戳字段,若记录要修改,则增加该记录的版本字段,在提交时与原数据进行比较,若大于则说明可以正常提交,否则说明该记录已经被修改,需要进行检查。时间戳也同样。

悲观锁说明:比如事务T1通过SQL语句"Select user.name from user as user where user.ID=1 for update"来查找记录,则此时满足条件的记录全部被锁定,若事务T2通过SQL语句“Selct user.name from user where user.ID=1 for update”,则事务T2只能等式待事务T1完成后才能执行。

 

 

在数据库原理中,又可以把读锁和写锁分为长锁短锁

长锁:在整个事务范围内,该锁都有效。比如事务T1中有对数据D1的长写锁,则表示在T1整个事务过程中,别的事务都无法取得对数据D1的更新权限,直到事务T1完成提交或者回滚。

短锁:只在数据查询的更新等操作时有效,数据操作完毕马上释放。释放完毕后,别的事务即可以申请对该数据的锁。

谓词锁:锁定满足查询条件

数据库的标准隔离级别及锁定义:         

隔离级别 记录上的写锁是长期的 记录上的读锁是长期的 谓词上的读锁和写锁是长期的
Read Uncommitted 无读锁 无谓词锁
Read Committed 短期读谓词锁
长期写谓词锁
Repeatable Read 短期读谓词锁
长期写谓词锁
Serilizable 长期读谓词锁
长期写谓词锁

 

  Read Uncommitted:标准定义中,在该级别中不允许存在更新操作,也就是说在该级别的所有事务都是只读的,但是这种级别允许读取别的事务已经更改但还没有提交的数据,这样就会导致脏读。比如事务A更改了user的用户名为userA,但是还未提交,但此种级别的事务B读取了该数据,但是事务A又失败了,导致回滚,这样事务B其实读到了无用的中间数据。

  Read Committed:该级别会导致两种错误读取:

    1.不可重复读取:假设事务A已经读取了某条数据,因为是短期读锁,导致事务A释放对数据的锁,此时事务B申请到了对事务A已经读取事务的写锁,并更改数据并提交,当事务A再次读取该数据时,数据已经改变。

    2.更新丢失:比如事务A和事务B同时读取了某条数据,初始值都是100,事务A的意图是在100的基础上加上40,得到结果140,事务B的意思是在这条数据上增加50,按照正常的模式,得到的最终值应该是190,但是由于数据事务A和B都读到的是初始数据,事务A提交后,此时该数据应该是140,但是B已经读取了旧数据100,然后B再更新,导致结果150,这样就产生了错误的结果,序列如下:r1(a,100)r2(a,100)w1(a,140)c1 w2(a,150)c2,其中r1表示事务A的读,W1表示事务A的写,B也同样。

  Repeatable Read:在该隔离机制下,屏蔽了以上会出现的问题。但是该级别使用了短期的读谓词锁,这样会导致幻像读取,比如事务A读取了ID>0的所有记录。数据库可能需要装入整装表逐个遍历该张表的所有记录,完成每一条记录的读取和where条件的比对,然后谓词读锁释放,但当此时,事务A未提交事务,此进事务B插入了一条数据满足ID>0,但是因为事务A已经释放了ID>0的谓词锁,会导致检测不到事务B的提交数据。这种幻像读在Serilizable中可以去除,因为在Seriliable中,使用了长期读谓词锁,这样事务B插入数据时,会导致锁冲突,从而避免了幻像读取。

 

    以上只是本人对数据库的一些简单理解,如果有什么不正确的地方,欢迎大家指正。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics