oracle深入体系结构 笔记

[align=center][b]第六章:锁[/b][/align]
[b]悲观锁定[/b]:在试图更新前就把数据锁起来叫悲观锁定
仅用于有连接和有状态的环境,也就是说,你的应用与数据库有一条连续的连接,而且至少在事务生存期中只有你一个人使用这条连接

[b]乐观锁定[/b](optimistic locking) ,即把所有锁定都延迟到即将执行更新之前才做

[b]乐观锁定方式[/b]:
1、 使用版本列的乐观锁定:在表中新增一列,每更新一次都更新这列,然后在更新时会拿旧值和新值比较,如果相同就更新
2、 使用校验和的乐观锁定:不推荐使用,很麻烦要计算出散列值
3、 使用 ORA_ROWSCN的乐观锁定 比如select t.*,ora_rowscn from one t
默认情况下,一个块上的多行会共享相同的ORA_ROWSCN值,如果不默认必须启用ROWDEPENDENCIES再重新创建这个段(ORA_ROWSCN建立在内部Oracle系统时钟(SCN)基础上。在Oracle中,每次提交时,SCN都会推进(其他情况也可能导致SCN推进,要注意,SCN只会推进,绝对不会后退)。这个概念与前面在获取数据时得到ORA_ROWSCN的方法是一样的,更新数据时要验证SCN未修改过。之所以我会强调这一点(而不是草草带过),原因是除非你创建表时支持在行级维护ORA_ROWSCN,否则Oracle会在块级维护。也就是说,默认情况下,一个块上的多行会共享相同的ORA_ROWSCN值。如果更新一个块上的某一行,而且这个块上还有另外50行,那么这些行的ORA_ROWSCN也会推进。这往往会导致许多假警报,你认为某一行已经修改,但实际上它并没有改动)

[b]阻塞[/b]:如果一个会话持有某个资源的锁,而另一个会话在请求这个资源,就会出现阻塞

[b]1. 阻塞的INSERT[/b]
INSERT阻 塞的情况不多见。最常见的情况是,你有一个带主键的表,或者表上有惟一的约束,但有两个会话试图用同样的值插入一行。如果是这样,其中一个会话就会阻塞, 直到另一个会话提交或者回滚为止:如果另一个会话提交,那么阻塞的会话会收到一个错误,指出存在一个重复值;倘若另一个会话回滚,在这种情况下,阻塞的会 话则会成功。还有一种情况,可能多个表通过引用完整性约束相互链接。对子表的插入可能会阻塞,因为它所依赖的父表正在创建或删除倘若没有对外键加索引,Oracle会使用表锁来保证外键关系,如果你不知道这一点,你的应用就会性能很差

[b]死锁[/b]
如果你有两个会话,每个会话都持有另一个会话想要的资源,此时就会出现死锁(deadlock)。例如,如果我的数据库中有两个表A和B,每个表中都只有一行,就可以很容易地展示什么是死锁。我要做的只是打开两个会话(例如,两个SQL*Plus会话) 。在会话A中更新表A,并在会话B中更新表B。现在,如果我想在会话B中更新表A,就会阻塞。会话A经锁定了这一行。这不是死锁;只是阻塞而已。我还没有遇到过死锁,因为会话A还有机会提交或回滚,这样会话B就能继续
导致死锁的头号原因是外键未加索引,第二号原因是表上的位图索引遭到并发更新
在以下两种情况下,Oracle在修改父表后会对子表加一个全表锁:
如果更新了父表的主键(倘若遵循关系数据库的原则,即主键应当是不可变的,这种情况就很
少见),由于外键上没有索引,所以子表会被锁住。
如果删除了父表中的一行,整个子表也会被锁住(由于外键上没有索引)

[b]锁的种类[/b]
[b]TX锁(事务锁)[/b]:事务发起第一个修改时会得到TX锁(事务锁),而且会一直持有这个锁,直至事务执行提交(COMMIT)或回滚(ROLLBACK)

Oracle中的锁定过程如下:
(1) 找到想锁定的那一行的地址。
(2) 到达那一行。
(3) 锁定这一行(如果这一行已经锁定,则等待锁住它的事务结束,除非使用了NOWAIT选项)

TM (DML Enqueue)锁
TM锁(TM lock)用于确保在修改表的内容时,表的结构不会改变

更新一个表时,Oracle会为它加一个TM锁,以防止其他会话删除这个表(实际上,也会防止其他会话对这个表执行大多数DDL) 。在我们修改的各个块上会加上TX锁,这样就能告诉别人哪些数据是“我们的”。数据库采用DDL锁来保护对象,这样当我们正在修改这些对象时,别人不会同时对它们进行修改。数据库在内部使用了闩和锁(lock)来保护自己的结构

Oracle没有脏读的概念,当oracle读数据时,只会读取那个时间点的所有数据,如果那个时间点后做了更新,那么就读更新前数据,这样避免了脏读
其他数据库如果隔离级别是READ COMMITTED,还是有可能脏读,比如有三个账户A B C,分别有500 200 100 ,现在转账A到C 400,现在有个用户读,读了A和B后,执行转账,此时用户读访问C被锁,只有commit后才能访问,但是commit后C的钱为500了,结果用户读的账户总额成了500+200+500


REPEATABLE READ oracle使用读取同一时间点数据
其他数据库则使用共享读锁,这样性能很低,而且可能发生死锁


ORACE的隔离级别
ORACE提供了SQ92标准中的read committed和seriaizabe,同时提供了非SQ92标准的read-ony。
read committed:
• 这是ORACE缺省的事务隔离级别。
• 事务中的每一条语句都遵从语句级的读一致性。
• 保证不会脏读;但可能出现非重复读和幻像。
seriaizabe:(串行执行事务,并发性最小)
• 简单地说,seriaizabe就是使事务看起来象是一个接着一个地顺序地执行。
• 仅仅能看见在本事务开始前由其它事务提交的更改和在本事务中所做的更改。
• 保证不会出现非重复读和幻像。
• Seriaizabe隔离级别提供了read-ony事务所提供的读一致性(事务级的读一致性),同时又允许DM操作。

seriaizabe的性能很低,一是事务必须要串行;二是在寻找同一时间点的数据需要访问许多的undo段,增加IO,当然这种情况在read committed中也有,但是在seriaizable情况更严重

语句级的读一致性
ORACE保证语句级的读一致性,即一个语句所处理的数据集是在单一时间点上的数据集,这个时间点是这个语句开始的时间。
一个语句看不见在它开始执行后提交的修改。
对于DM语句,它看不见由自己所做的修改,即DM语句看见的是它本身开始执行以前存在的数据。
事务级的读一致性

事务级的读一致性保证了可重复读,并保证不会出现幻像。
设置隔离级别

设置一个事务的隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET TRANSACTION READ ONLY;
设置增个会话的隔离级别
ATER SESSION SET ISOLATION_LEVE SERIALIZABLE;
ATER SESSION SET ISOLATION_LEVE READ COMMITTED;


set autotrace on statistics


事务中几个不好的行为:
频繁的提交事务(性能影响、错误(檫掉undo信息))
使用自动提交(jdbc中在update后会自动提交)


Oracle支持分布式事务,利用的2pc协议
分布式事务限制:
不能在数据库链接上发出commit
不能在数据库链接上执行DDL语句
不能在数据库链接上发出savepoing


自治事务:它能独立于其父事务提交或回滚
Create or replace procedure XX
As
Pragma autonomous_transaction;
Begin
Insert into values(‘haha’);
Commit;
End;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值