全面解析oracle中的锁机制2

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 默认情况下 T@ora>create table t1 as select * from t ; Table created. Elapsed: 00:00:00.

默认情况下
T@ora>create table t1 as select * from t ;

Table created.

Elapsed: 00:00:00.07
T@ora>select rowid,ora_rowscn,a from t1;

ROWID                         ORA_ROWSCN          A
------------------                      ----------             ----------
AAARN5AAGAAAXHcAAA   45387504          1
AAARN5AAGAAAXHcAAB   45387504          2
AAARN5AAGAAAXHcAAC   45387504          3
AAARN5AAGAAAXHcAAD   45387504          4
AAARN5AAGAAAXHcAAE   45387504          5
AAARN5AAGAAAXHcAAF   45387504          6
AAARN5AAGAAAXHcAAG   45387504          7
AAARN5AAGAAAXHcAAH   45387504          8
AAARN5AAGAAAXHcAAI   45387504          9
AAARN5AAGAAAXHcAAJ   45387504         10

10 rows selected.

Elapsed: 00:00:00.20
T@ora>update t1 set a = 0 where a <3;

2 rows updated.

Elapsed: 00:00:00.01
T@ora>commit;

Commit complete.

Elapsed: 00:00:00.00
T@ora>select rowid,ora_rowscn,a from t1;

ROWID                           ORA_ROWSCN          A
------------------                          ----------          ----------
AAARN5AAGAAAXHcAAA   45387522          0
AAARN5AAGAAAXHcAAB   45387522          0
AAARN5AAGAAAXHcAAC   45387522          3 《----这里开始后面的记录都没做修改,但是ora_rowscn却改变了
AAARN5AAGAAAXHcAAD   45387522          4
AAARN5AAGAAAXHcAAE   45387522          5
AAARN5AAGAAAXHcAAF   45387522          6
AAARN5AAGAAAXHcAAG   45387522          7
AAARN5AAGAAAXHcAAH   45387522          8
AAARN5AAGAAAXHcAAI   45387522          9
AAARN5AAGAAAXHcAAJ   45387522         10

10 rows selected.
增加ROWDEPENDENCIES 
T@ora>create table t2 ROWDEPENDENCIES  as select * from t ;

Table created.

Elapsed: 00:00:00.06
T@ora>select rowid,ora_rowscn,a from t2;

ROWID                              ORA_ROWSCN          A
------------------                      ----------               ----------
AAARN6AAGAAAXHkAAA   45387561          1
AAARN6AAGAAAXHkAAB   45387561          2
AAARN6AAGAAAXHkAAC   45387561          3
AAARN6AAGAAAXHkAAD   45387561          4
AAARN6AAGAAAXHkAAE   45387561          5
AAARN6AAGAAAXHkAAF   45387561          6
AAARN6AAGAAAXHkAAG   45387561          7
AAARN6AAGAAAXHkAAH   45387561          8
AAARN6AAGAAAXHkAAI   45387561          9
AAARN6AAGAAAXHkAAJ   45387561         10

10 rows selected.

Elapsed: 00:00:00.03
T@ora>update t2 set a = 0 where a <3;

2 rows updated.

Elapsed: 00:00:00.01
T@ora>commit;

Commit complete.

Elapsed: 00:00:00.00
T@ora>select rowid,ora_rowscn,a from t2;

ROWID                          ORA_ROWSCN          A
------------------                         ----------         ----------
AAARN6AAGAAAXHkAAA   45387578          0
AAARN6AAGAAAXHkAAB   45387578          0
AAARN6AAGAAAXHkAAC   45387561          3 《--没有修改的scn就不会改变
AAARN6AAGAAAXHkAAD   45387561          4
AAARN6AAGAAAXHkAAE   45387561          5
AAARN6AAGAAAXHkAAF   45387561          6
AAARN6AAGAAAXHkAAG   45387561          7
AAARN6AAGAAAXHkAAH   45387561          8
AAARN6AAGAAAXHkAAI   45387561          9
AAARN6AAGAAAXHkAAJ   45387561         10

存储空间的影响,dump出来就可以看到2个存储结构不一样
普通表
tab 0, row 0, @0x1f1e
tl: 8 fb: --H-FL-- lb: 0x2  cc: 2
col  0: [ 1]  80
col  1: [ 2]  c1 02


2个number类型
tab 0, row 0, @0x1edc
tl: 14 fb: --H-FL-- lb: 0x2  cc: 2
dscn 0x0000.02b48f29
col  0: [ 1]  80
col  1: [ 2]  c1 02

多出6个字节记录dscn。


将SCN 转换为墙上时钟时间:
使用透明的ORA_ROWSCN 列还有一个好处:可以把SCN 转换为近似的墙上时钟时间(有+/–3 秒的偏差),从而发现行最后一次修改发生在什么时间。例如,可以执行以下查询:


ops$tkyte@ORA10G> select deptno, ora_rowscn, scn_to_timestamp(ora_rowscn) ts2 from dept;


DEPTNO ORA_ROWSCN          TS
----------     ----------                -------------------------------
10            34676381         25-APR-05 02.37.04.000000000 PM

20            34676364         25-APR-05 02.34.42.000000000 PM
30           34676364          25-APR-05 02.34.42.000000000 PM
40           34676364          25-APR-05 02.34.42.000000000 PM


在此可以看到,在表的最初创建和更新DEPTNO = 10 行之间,我等了大约3 分钟。不过,从SCN 到墙上时钟时间的这种转换有一些限制:数据库的正常运行时间只有5 天左右。例如,如果查看一个“旧”表,查找其中最旧ORA_ROWSCN(注意,在此我作为SCOTT 登录;没有使用前面的新表):


scott@ORA10G> select min(ora_rowscn) from dept;


MIN(ORA_ROWSCN)
---------------
364937


如果我试图把这个SCN 转换为一个时间戳,可能看到以下结果(取决于DEPT 表有多旧!):


scott@ORA10G> select scn_to_timestamp(min(ora_rowscn)) from dept;


select scn_to_timestamp(min(ora_rowscn)) from dept
*
ERROR at line 1:
ORA-08181: specified number is not a valid system change number
ORA-06512: at "SYS.SCN_TO_TIMESTAMP", line 1
ORA-06512: at line 1


所以从长远看不能依赖这种转换。

3、乐观悲观锁总结:

到底是用乐观锁呢还是悲观锁呢?现实生产环境中,使用乐观锁的机会远多于悲观锁,最大的原因就是悲观锁需要与数据库建立一个连接,这个连接会耗费很多的资源,特别是在用户数超过一百以上,每个用户有一个连接,这样是不现实的。

一般用乐观锁定的版本戳,然后再加一个时间戳,这样一来,就可以查询到每一行最后一次修改的时间啦,真是省劲快捷,hash方法那个如果碰到LONG,LONG RAW,CLOB,BLOB这等大数据就死翘翘了。。

4、阻塞和死锁:

数据库中有5条常见的语句会发生阻塞,他们分别是:insert,update,delete,merge,select for update

对于一个阻塞的SELECT FOR UPDATE,解决方案很简单:只需增加NOWAIT 子句,它就不会阻塞了。这样一来, 你的应用会向最终用户报告,这一行已经锁定。另外4 条DML 语句才有意思。我们会分别分析这些DML 语句,看看它们为什么不应阻塞,如果真的阻塞了又该如何修正。

1、阻塞的insert:

INSERT 阻塞的情况不多见。最常见的情况是,你有一个带主键的表,或者表上有惟一的约束,但有两个会话试图用同样的值插入一行。如果是这样,其中一个会话就会阻塞, 直到另一个会话提交或者回滚为止:如果另一个会话提交,那么阻塞的会话会收到一个错误,指出存在一个重复值;倘若另一个会话回滚,在这种情况下,阻塞的会话则会成功。还有一种情况,可能多个表通过引用完整性约束相互链接。对子表的插入可能会阻塞,因为它所依赖的父表正在创建或删除。如果应用允许最终用户生成主键/惟一列值,往往就会发生INSERT 阻塞。为避免这种情况,最容易的做法是使用一个序列来生成主键/惟一列值。序列(sequence)设计为一种高度并发的方法,用在多用户环境中生成惟一键。如果无法使用序列,那你可以使用以下技术,也就是使用手工锁来避免这个问题,这里的手工锁通过内置的DBMS_LOCK 包来实现。

当然,如果表的主键是一个INTEGER,而你不希望这个主键超过1 000 000 000,那么可以跳过散列,直接使用这个数作为锁ID。要适当地设置散列表的大小(在这个例子中,散列表的大小是1 024),以避免因为不同的串散列为同一个数(这称为散列冲突)而人工地导致资源忙消息。散列表的大小与特定的应用(数据)有关,并发插入的数量也会影响散列表的大小。最后,还要记住,尽管Oracle 有无限多个行级锁,但是enqueue 锁(这是一种队列锁)的个数则是有限的。如果在会话中插入大量行,而没有提交,可能就会发现创建了太多的enqueue 队列锁,而耗尽了系统的队列资源(超出了ENQUEUE_RESOURCES 系统参数设置的最大值),因为每行都会创建另一个enqueue 锁。如果确实发生了这种情况, 就需要增大ENQUEUE_RESOURCES 参数的值。还可以向触发器增加一个标志,允许打开或关闭这种检查。例如,如果我准备插入数百条或数千条记录,可能就不希望启用这个检查。

2、阻塞的update、delete和merge:

select for updatre nowait 能够避免丢失更新的问题。他能验证你自从获取数据到执行修改这期间没有别的事务来修改这个数据库,锁住这一行,防止update和delect阻塞。不论是乐观锁还是悲观锁,都会用这一句实现这些功能,只是悲观锁会在你获取这一行之后就执行了锁定,而乐观锁是在即将提交的时候才执行的。

3、死锁:

一般来看死锁的出现常见原因有两个:外键未加索引 表上的位图索引遭到并发更新

在以下情况,oracle修改父表后会对字表加一个索引:1、果更新了父表的主键,因为外键上没有索引,所以子表上会被锁住;2、删除了父表的一行,子表也会被锁住。

以上这种锁,只有在执行对应的DML语句是才会发生,而不是整个事务期间都会锁住字表,这样可以减少死锁的可能性,但是即使这样,死锁还是可以发生的。

删除父表中的一行可能导致子表被锁住,由此产生的问题更多。我已经说过,如果删除父表P 中的一行,那么在DML 操作期间,子表C 就会锁定,这样能避免事务期间对C 执行其他更新(当然,这有一个前提,即没有人在修改C;如果确实已经有人在修改C,删除会等待)。此时就会出现阻塞和死锁问题。通过锁定整个表C,数据库的并发性就会大幅下降,以至于没有人能够修改C 中的任何内容。另外,出现死锁的可能性则增加了,因为我的会话现在“拥有”大量数据,直到提交时才会交出。其他会话因为C 而阻塞的可能性也更大;只要会话试图修改C 就会被阻塞。因此,我开始注意到,数据库中大量会话被阻塞,这些会话持有另外一些资源的锁。实际上,如果其中任何阻塞的会话锁住了我的会话需要的资源,就会出现一个死锁。在这种情况下,造成死锁的原因是:我的会话不允许别人访问超出其所需的更多资源(在这里就是一个表中的所有行)。

相关文章
|
1月前
|
Java 数据库连接 开发者
Java中的异常处理机制深度解析
【8月更文挑战第13天】本文旨在深入探讨Java编程语言中一个至关重要的组成部分——异常处理机制。我们将从基本概念入手,逐步展开讨论异常处理在Java语言设计中的角色和重要性,以及如何正确利用这一机制来提高代码的健壮性和可维护性。文章将通过分析异常处理的最佳实践,揭示如何在复杂的应用程序中有效地管理和处理错误情况。
|
3天前
|
Java 开发者
深入解析Java中的异常处理机制
本文将深入探讨Java中异常处理的核心概念和实际应用,包括异常的分类、捕获、处理以及最佳实践。我们将通过具体示例展示如何有效使用try-catch块、throws关键字和自定义异常类,以帮助读者更好地理解和应用Java异常处理机制。
10 1
|
3天前
|
Java 程序员 开发者
Java中的异常处理机制深度解析
本文旨在深入探讨Java中异常处理的机制,包括异常的分类、如何捕获和处理异常,以及自定义异常的最佳实践。通过实例讲解,帮助读者更好地理解如何在Java编程中有效管理和利用异常处理来提高代码的健壮性和可维护性。
|
1月前
|
存储 SQL 关系型数据库
深入解析MySQL事务机制和锁机制
深入解析MySQL事务机制和锁机制
|
1月前
|
存储 缓存 NoSQL
深入解析Memcached:内部机制、存储结构及在大数据中的应用
深入解析Memcached:内部机制、存储结构及在大数据中的应用
|
1月前
|
监控 Oracle 关系型数据库
"深度剖析:Oracle SGA大小调整策略——从组件解析到动态优化,打造高效数据库性能"
【8月更文挑战第9天】在Oracle数据库性能优化中,系统全局区(SGA)的大小调整至关重要。SGA作为一组共享内存区域,直接影响数据库处理能力和响应速度。本文通过问答形式介绍SGA调整策略:包括SGA的组成(如数据缓冲区、共享池等),如何根据负载与物理内存确定初始大小,手动调整SGA的方法(如使用`ALTER SYSTEM`命令),以及利用自动内存管理(AMM)特性实现智能调整。调整过程中需注意监控与测试,确保稳定性和性能。
104 2
|
17天前
|
Java Spring
🔥JSF 与 Spring 强强联手:打造高效、灵活的 Web 应用新标杆!💪 你还不知道吗?
【8月更文挑战第31天】JavaServer Faces(JSF)与 Spring 框架是常用的 Java Web 技术。本文介绍如何整合两者,发挥各自优势,构建高效灵活的 Web 应用。首先通过 `web.xml` 和 `ContextLoaderListener` 配置 Spring 上下文,在 `applicationContext.xml` 定义 Bean。接着使用 `@Autowired` 将 Spring 管理的 Bean 注入到 JSF 管理的 Bean 中。
29 0
|
17天前
|
JavaScript 前端开发 开发者
深入解析Angular装饰器:揭秘框架核心机制与应用——从基础用法到内部原理的全面教程
【8月更文挑战第31天】本文深入解析了Angular框架中的装饰器特性,包括其基本概念、使用方法及内部机制。装饰器作为TypeScript的关键特性,在Angular中用于定义组件、服务等。通过具体示例介绍了`@Component`和`@Injectable`装饰器的应用,展示了如何利用装饰器优化代码结构与依赖注入,帮助开发者构建高效、可维护的应用。
20 0
|
1月前
|
Java 开发者
深入解析Java中的异常处理机制
在Java的世界中,异常处理是维护程序健壮性的基石之一。本文将通过实例演示和理论分析相结合的方式,探讨Java异常处理机制的工作原理及其最佳实践。我们将从异常的基本概念出发,逐步深入到异常类的层次结构、捕获异常的策略以及自定义异常的使用场景,旨在为读者提供一个全面而深入的视角来理解和应用Java中的异常处理。
24 2
|
24天前
|
负载均衡 监控 网络协议

热门文章

最新文章

推荐镜像

更多