首页 > 代码库 > Oracle锁总结
Oracle锁总结
《oracle的锁》
在数据库中必须要了解的几点:
1、事务是数据库的核心,他们是好东西
2、应该延迟到适当的时刻才提交。不要太快提交,以避免对系统带来压力,这是因为,即使事务很长或很大,也一般不会对系统造成压力。相应的原则是: 在必要时才提交,不要提前。事务的大小只应该根据业务逻辑来定。
3、只要需要,就应该尽可能长时间的保持对数据所加的锁。这些锁是你能用的工具,而不是让你退避三舍,锁并不是什么稀有资源,恰恰相反,只要需要, 你就应该长期的保持数据上的锁。锁并不稀少,而且他们可以防止其他会话修改信息;
4、在Oracle中,行级锁 没有相关的开销,一点都没有。不论有一个行锁,还是有10000个行锁,专用于锁定这个信息的资源数都是一样的。当然,与修改一 行相比,修改10000行要做的工作肯定多得多,但是锁住10000行所需的资源数与锁住一行所需的资源数完全相同,这是一个固定的常量;
5、不要以为锁升级会对系统更好(例如:使用表锁而不是行锁)。在Oracle中,锁升级对系统没有任何好处,也不会节省任何资源。有时候我们会使用表 锁,例如在批处理中,使用表锁是为了确保在这种情况下你能访问你的批处理程序所需的所有资源;
6、可以同时得到并发性和一致性。数据读取器不会被数据写入器阻塞。数据写入器也不会被数据读取器阻塞。这是Oracle与大多数其他关系数据库之间的根 本区别之一;
一、Oracle锁的种类:
1.1、悲观锁:
这种方式在用户修改数值之前就已经生效了,例如:用户打算对他选择的且在屏幕上可见的某个特定行执行更新(比如通过点击某个按钮),该行就会被加上一个锁,这个行锁会一直持续应用到应用程序在数据库中执行用户的修改并提交的时候;
注意:悲观锁仅适用于有状态或有连接的环境。也就是说你的应用与数据库直接有一个持续的连接,而且只有你一个人在使用这条连接(至少是在你的事务的生命周期内);
1.2、乐观锁:
即把所有锁定的动作都延迟到即将执行更新之前才进行,换句话说,我们会修改屏幕上的信息而不需要先锁住他,;(这种锁方法在所有环境下都可以,但是采用这种方法,更新失败的可能性就会加大)也就说,用户要更新他的数据行时,却发现数据已经被修改过,那他就必须从头再来;
①:使用版本列的乐观锁
这个方法很容易实现,如果你想保护数据库表不出现丢失更新问题,就在对应的每个表上增加一列,这一列一般是number 或 date/timestamp类型的列,通常通过表上的一个行触发器来维护。(最佳的方式是通过update语句本身来维护)
②:使用总和检验的乐观锁
这版本列方法很相似,不过他是基于数据本身来计算得出一个“虚拟”的版本列,为了帮助解释有关总和检验或散列函数的目标和概念;
注意:对大多数应用来说,都建议采用乐观并发控制,而在乐观并发控制的方法中,更倾向于使用版本列方法,来增加一个时间戳列(而不只是一个number)
2、阻塞:
数据中有5个常见的DML语句可能会引起阻塞,他们是:insert update delete merge 和 select for update;
对于一个阻塞的seelct for update 解决方案:只需要增加nowait字句,他就不会阻塞了;
2.1、阻塞的insert
insert阻塞的情况不多见,最常见的的情况是:你有一个带主键的表,或者表上有唯一性约束,单有两个回话试图用同样的值插入一行,如果这样,其中就有一个会话就会被阻塞;
注意:发生insert阻塞通常是因为应用允许最终用户生成主键/唯一列值。为了避免这种情况,最容易的做法就是使用一个序列或sys_guid()内置函数来生成主键/唯一列值;
2.2、阻塞的merge update delete
在一个交互式应用中,可以从数据库查询数据,允许最终用户处理这些数据,再把它放回到数据库中,此时如果发生update或delete阻塞,就说明你的代码中可能存在一个丢失更新问题;可以通过使用select for update nowait查询来避免这个问题。这个查询能做到:验证自从你查询数据之后数据未被修改(防止丢失更新);锁住行(防止update或delete被阻塞)
不论是悲观锁还是乐观锁都可以利用select for update nowait查询来验证行未被修改。悲观锁会在用户有意修改数据那一刻使用这条语句。乐观锁则在即将在数据库中更新数据时使用这条语句。这样不仅能解决应用中的阻塞问题,还可以修正数据完整性问题;
注意:merge本质上其实就是insert 和 update
3、死锁
导致死锁的重要原因就是:外键未加索引,第二个原因是表上的位图索引遭到并发更新
4、Oracle的锁类型
Oracle主要有3种类型的锁:
4.1、DML锁:DML数据操纵语言,一般是指:select insert update merge delete
DML锁机制允许并发执行数据修改,例如:DML锁可能是特定数据行上的锁,或者是锁定表中所有行的表级锁;
4.2、DDL锁:DDL数据定义语言,一般是指:create alter语句
DDL锁可以保护对象结构定义
注意:内部锁和闩:Oracle使用这些锁来保护其内部数据结构。(闩是Oracle采用的一种轻量级的低级串行化设备,功能上类似于锁)其实,闩是数据库中导致竞争的一个常见的原因;
5、DML锁:用于确保一次只有一个人能修改某一行,而且这时别人不能删除这个表;
①:TX锁----事务锁
事务的发动是自动的,TX锁会被一直持有,直至事务执行提交(commit)或回滚(rollback)。TX锁被用作一种排队机制,使得其他回话可以等待这个事务完成;
②:TM锁----
TM锁用于确保在修改表的内容时,表的结构不会改变。例如:如果你已经更新了一个表中的行,那同时也会得到这个表的一个TM锁,这会防止另一个用户在该表上执行DROP或ALTER命令;
(在Oracle11G R2及更高的版本中,可以设置ddl_lock_timeout当DDL等待)
6、DDL锁:在DDL操作中会自动为对象加锁,从而保护这些对象不会被其他会话所修改;
例如,如果我执行一个DDL操作alter table t,通常表T上就会有一个排他DDL锁,以防止其他会话得到这个表的DDL锁和TM锁;
有3钟类型的DDL锁:
①:排他DDL锁:
这会防止其他会话得到它们自己的DDL锁或TM(DML)锁,这说明,在DDL操作期间可以查询一个表,但是无法以任何方式修改这个表;
②:共享DDL锁:
这些锁会保护锁引用的对象的结构,使之不会被其他会话修改,但是允许修改数据;
③:可中断解析锁:
这些锁允许一个对象(如共享池中缓存的一个查询计划)向其他对象注册其依赖性。
7、闩:闩是轻量级的串行设备,用于协调对共享数据结构、对象和文件的多用户访问;(闩是一种轻量级的锁)
8、互斥锁:是一种与闩非常类似的串行化设备,互斥锁是数据库中使用另一种串行化设备;
查看锁定的对象、用户名和会话
SQL> select lo.oracle_username,do.object_name,s.logon_time,lo.process,s.sid as session_id from v$locked_object lo,v$session s,dba_objects do where lo.session_id = s.sid and do.object_id = lo.OBJECT_ID;
Oracle的Select For Update语句可以实现在读取数据后马上锁定相关资源,防止被其他session修改数据的目的
手动锁定:select ... for update语句
select * from table_sfu where a = 1 for update; ----锁定第一行数据(只有commit后才会解锁)
本文出自 “笨小孩的dba之路” 博客,请务必保留此出处http://fengfeng688.blog.51cto.com/4896812/1934428
Oracle锁总结