锁定机制:
每个数据库的封锁机制不一样,了解工作原理才能开发出完整的应用程序。
Sybase机制:数据更新会导致其他访问都挂起,没有并行可言,速度和正确不可兼得。
Informix机制:实现行级封锁的同时,需要消耗大量的内存和时间,容易导致系统瘫痪。
Oracle机制注意点:
事务处理是数据库的全部工作,他们是好的事务。
只要有需要,就要就应该推迟提交,只在必须提交时才提交,事务应该和商务逻辑规则大小一样。
只要有需要,就应该对数据锁定,他是oracle的工具,不是要避免的东西,对oracle来说,他不是稀有资源。
oralce的行级锁定不消耗资源。
不应该无谓的扩大你的锁定范围,如:只需要行级锁定的,你使用表锁定。
丢失更新:
当以下事务发生时,如果没有使用锁定机制,将会导致丢失更新:
用户1查询数据行A
用户2查询数据行A
用户1更改数据行A,提交更改
用户2更改数据行B,提交更改
此时如果只是用简单的select,update机制,那么用户1的更新将丢失,被用户2覆盖。
悲观封锁
实现方法:在用户1发出更改意图时(选定更改行),通知oracle锁定该行(select
* from tab where id = * for update
nowait),此时会有三种情况发生:
该行被锁定成功,结果被选出,其他用户无法更新。
如果其他用户正锁定该行,在修改过程中,会得到“resource
busy”的错误,必须等待该用户完成操作。
选到0行结果,这是因为在已经有用户在你首次查询之后对改行数据进行了更新,这时需要你重新查询(requery)来获得最新的信息,再进行操作。
乐观封锁:
直接使用update:
update tab set column1 := A,column2 := B where column1 = C and
column2 = D;
如果该行在查询到更改这段时间内已被更新,那么update的行数就为0,否则为1.
可以根据该值,商务规则,作出相应的弥补措施。
总结:
当使用悲观锁定的时候,为了避免持锁用户长时间锁定,可以用程序实现定时释放锁,或者通过oracle的resource
profile来总之用户对话。
锁定不会导致其他的读操作,这是oracle的有点。
阻塞:
四个DML语句造成的阻塞:update,delete,insert,select
for update
1. select for update: 加入 nowait就可以
2. insert的阻塞:
原因:多个用户试图在具有唯一性约束的列中插入相同的值。
解决方法:用oracle 提供的sequence来取值
3. update和delete的阻塞:
原因:试图更新一个已经被其他用户更新的行
解决方法:select for update
检测是否被更新过,同时加以锁定。
死锁:
在oracle中很少发生,发生情况:
A表中有一行数据,B表中有一行数据
会话A更新A表,会话B更新B表,此时会话B又去更新A表,会话A又去更新B表,就出现了死锁;A表的更新队列中会话B在等待会话A提交,B表的更新队列中会话A在等待会话B提交。
实际使用中促成死锁的个别案例:
更新父表主键,字表因为没有索引而被锁定 -
所以主键跟换是禁止的做法
删除父表行,整个子表也将被锁定(没有索引),所有更新子表的会话会被阻塞,只要有一个会话阻塞了更新父表的会话,就会产生死锁。
总结:避免死锁和系统挂起的问题:
不要更改父表主码
不要删除父表数据
索性不要建立父子关系
锁定类型:
DML锁定:select,insert,delete,update,此类锁定会触发2类锁定:
行级锁定(TX锁定):锁定特定行,防止其他用户修改内容
表级锁定(TM锁定):锁定整个表,防止其他用户更改表结构,drop,alter。
DDL锁定:create,
alter;DDL执行的过程可以被认为:
Begin
commit;
DDL
Statement;
commit;
Exception
rollback;
End;
所以执行DDL意味着执行提交现存事务,如果要避免可以应用自治事务。
DDL锁定有三类:
DDL独占锁定:TM锁定,同时不可修改内容(一般使用)
DDL共享锁定:TM锁定,但是可以修改内容
可打破的分析锁定:不可防止
内部锁定和锁存器:保护内部数据结构的锁定:当内存中数据结构改变时,锁存用来保护内存数据结构。
分布式锁定:保持多个节点上资源一致,ops(oracle并行服务器)独有
PCM(并行缓冲器管理)锁定:保护多个实例之间高速缓冲区里数据块,,ops(oracle并行服务器)独有
手动封锁和用户自定义锁定:
之前的TX和TM锁定都是系统定义的自动锁定,下面介绍一下用户自定义锁定方式:
借助SQL语句锁定数据
借助DBMS_Lock包创建封锁
为什么需要手动锁定:
select for update, 为了更新行锁定
Lock table in exculusive mode
表锁定,大量更新表的数据时使用,保证不被其他用户阻塞。
试图控制并行访问oracle以外资源的队列(借助DBMS_Lock包)