数据库
首页 > 数据库> > Oracle专家高级编程 第三章 封锁和并行性

Oracle专家高级编程 第三章 封锁和并行性

作者:互联网

锁定

锁是一种机制,管理共享资源的并行访问,也就是concurrent问题

当多个用户访问并更改数据或数据结构时,以适当的机制防止对相同的信息段进行修改

在Oracle中

封锁问题

丢失更新

举例

悲观封锁(悲观锁)

在修改值之前就要发挥作用,即默认当前行数据一定会修改

行被锁之后,另一个用户修改行的进程中, 会返回"ORA-00054 资源忙(Resource Busy)"的错误,该进程被阻塞,需要等待用户完成工作

乐观封锁(乐观锁)

select for update nowait

使用悲观锁,当前正在修改的数据已经被check out了,没人能对其进行修改

行锁不会对其他用户的读取造成限制

阻塞

当一个会话请求另一个会话保持的资源时,会发生阻塞,它会一直挂起

4个DML语句会在数据库中阻塞

被阻塞的插入

阻塞的update和delete

表示在代码中可能又了一个丢失更新的问题

试图更新一个其他用户已经在更新的行(已经被锁定)

通过select for update避免阻塞问题

死锁

Oracle死锁以后,会在服务器上创建一个跟踪文件,Oracle的死锁很少

对父表修改之后,Oracle将在子表上放置完整的表锁定

更新主键在RDMS中是一个巨大的"禁忌"

什么情况下不需要索引外码

锁定扩大

当发生锁定扩大情况时,系统要降低锁定到粒度

例如,数据库系统将一个表的100个行级锁定转换为单一的表级锁定,锁定扩大用于锁资源稀少的数据库中频繁使用

Oracle不会扩大锁定,使用锁定转换,或锁定提升

尽可能在最低一级使用锁定,如果使用 select for update子句,会创建两个锁定:

所有针对表的其他语句是允许的,另一个会使用LOCK TABLE X IN SHARE MODE将表变为只读

锁定类型

DML锁定

select,insert,update和delete,指定行锁定或者表锁定

DDL锁定

create,alter,DDL锁定保护对象结构的定义

内部锁定和锁存器(latch)

Oracle保护内部数据结构的锁定,分析一个查询并生成优化的查询方案时,它将"锁存"库高速缓存器,是轻量的低级船行化设备

分布式锁定

OPS使用的锁,用于保证不同的节点资源保持相互之间的一致,分布式锁由数据库实例所持有

PCM(并行缓冲器管理,Parallel Cache Management)

保护多个实例之间缓冲存储器中高速缓存数据块的锁

DML锁定

DML锁用于保证一行在一段时间内只有一个用户进行修改

TX(事务)锁定

事务初始化其第一次更改结果时获得,且一直保持,直到事务执行提交(COMMIT)或回滚(ROLLBACK)

它用作一个排队机制,使其他会话等待该事务完成

修改或者select for update的每一行指向一个相关的TX锁定

Oracle锁定的处理方式

在Oracle锁定数据的行时,一个事务ID与包含数据的块相关

物理属性参数

默认情况下,每个块的生命从一个或两个事务槽开始,一个块可以拥有同时活动的事务数由MAXTRANS所限制

也被块上空间可用性所限制,即受到逻辑和物理上的限制

适当增加INITRNANS给预期的并行事务的数量在块上留出充足的空间

TM(DML 入队)锁定

保证更改表的内容时,表的结构不会被更改

如果已经更新了一个表,将得到在那个表上的一个TM锁定,放置另一个用户在表上运行DROP或ALTER命令

若试图在已经拥有TM锁定的表上执行DDL,将得到错误信息

ORA-00054:resource busy and acquire with NOWAIT specified

系统中允许的TM锁定的总数是用户可配置的

它可以设置为0,不意味着用户的数据库变成只读的数据库,而是不允许DDL

使用alter table tablename,disable table lock命令批量删除TM锁

DDL锁定

DDL锁定在DDl操作期间自动针对对象放置,保护免于被其他会话更改

例如使用alter table命令时,DDL锁在DDL期间保持,这是由隐式提交(或提交/回滚对)包含的DDL语句完成

DDL总是提交,即使没有成功,可以使用自定义事务

3种类型的DDL锁定

独占的DDL锁定

防止其他会话自己获得DDL锁定或TM锁定,意味着在DDL操作期间查询一个表,但不能修改

共享DDL锁定

保护饮用对象的结构,防止被其他会话修改,允许对数据的修改

可打破的分析锁定

允许对象在一些对象上注册信任,如果执行针对该对象的DDL,Oracle检查已经注册依赖关系的对象列表,使其无效,不能防止DDL发生

持久化DDL语句期间所做的修改,完成后将应用更新到心的索引上,提高了数据可用性

其他类型使用共享DDL锁定,

锁定器和内部锁定(入队)

锁存器和排队时轻量的序列化设备,用于协调多用户对共享的数据结构、对象和文件的访问

锁存器

锁存器时在极短时间内,例如修改内存中数据结构时间内保持的锁定,来保护内存结构

没有排队额锁存器的等待者,只有不断重试

Oracle使用原子指令进行锁存器操作,设置和释放指令是原子化的,运行效率高

万一一个锁存器持有者不正常的死掉,可以清除,由PMON执行

入队

一个更加复杂的串行设备,与锁存器的区别在于允许请求者排队等待资源

入队可以在不同等级获得,可以拥有许多"共享"锁定,用不同"共享能力"的锁

手动封锁和用户自定义锁定

手动封锁

select for update,最常用

lock table 比较粗糙,很少使用,锁表不锁行,如果写入大批更新,影响表中大部分行,可以使用

lock table in exclusive mode

可以保证不被用户阻塞

创建自己的锁定

借助DBMS_LOCK包

可以用这个包串行化对Oracle外部资源的访问

例如一个消息例程,文件在外部,Oracle不能协调试图同时修改它的用户,可以引入DBMS_LOCK包

对一个文件打开、写入或关闭操作前,文件进入独占模式前,请求一个指定的锁定,关闭文件后,手动释放锁定(有点像ReentrantLock)

并行控制

数据库提供的函数集,允许许多用户同时访问和修改数据,锁定的实现大概可以决定应用程序的并行程度

并行控制胜过锁定,多版本,写入不阻塞读取,

事务隔离级别

脏读

允许读一个没有提交的,或"脏"数据

非重复读

读者在时间T1读取一行,试图的时间T2再次读取行,该行可能已经更改或者消失

幻象读

如果时间T1执行了一个查询,并在时间T2再次执行,附加的行可能已经添加到数据库,影响结果

Oracle还支持只读模式

Read Uncommitted 隔离等级

允许脏读,Oracle不利用脏读,其目标在于提供"迎合"非阻塞读取的标准

Read Committed 隔离等级(最常用的隔离级别)

一个事务只能读取在事务开始前提交的数据,没有脏读

支持非阻塞读取

Repeatable Read 隔离等级

获得一致性答案,给定查询的结果必须与有关的时间点是一致的

如果产生死锁,之后事务中的一个将成为牺牲者,被杀死

Oracle使用多版本,拥有语句级的读取一致性,读取不阻塞写入,没有死锁

预防丢失更新

Repeatable Read 的普通用法就是为了预防丢失更新

Oracle中,需要Repeatable Read,不是用 select for update nowait,而是将隔离等级设置为Serializable

Serializable事务,使得我们从语句级获得的读取一致性扩展到事务,事务中执行的每一个查询答案固定在事务开始的时间点

Serializable 隔离等级

最具限制性的事务隔离等级,事务之间互不可见,隔离代价

ORA-08177:can't serialize access for this transaction

不论何时试图更新从事务开始以后已经更改的行,都会获得这个消息,什么时候适合用该隔离级别

此方法的可伸缩行,足够运行全部的TPC-C(OLTP标准测试)

只读事务

类似于Serializable事务,区别在于不允许修改,不容易出现ORA-8177错误,该事务支持报告的需要

该事务可能会出现

ORA-1555 snapshot too old 错误,当其他人活跃的修改正在读取的数据,可能报此错误

标签:事务,编程,阻塞,并行性,修改,DDL,Oracle,锁定
来源: https://www.cnblogs.com/YC-L/p/14657561.html