Oracle锁2:DML操作和锁

Oracle为DML操作自动获取行锁和表锁,操作的类型决定了锁的行为,下面对DML操作锁的情况作了一个汇总:

SQL Statement Row Locks Table Lock Mode RS RX S SRX X
SELECT ... FROM table... —— none Y Y Y Y Y
INSERT INTO table ... Yes SX Y Y N N N
UPDATE table ... Yes SX Y(注) Y(注) N N N
MERGE INTO table ... Yes SX Y Y N N N
DELETE FROM table ... Yes SX Y(注) Y(注) N N N
SELECT ... FROM tableFORUPDATEOF ... Yes SX Y(注) Y(注) N N N
LOCK TABLE tableIN ... ——            
ROW SHARE MODE   SS Y Y Y Y N
ROW EXCLUSIVE MODE   SX Y Y N N N
SHARE MODE   S Y N Y N N
SHARE ROW EXCLUSIVE MODE   SSX Y N N N N
EXCLUSIVE MODE   X N N N N N

注:如果另一个事务和当前事务出现行冲突,则需要等待

下面阐述当行被查询和修改时会涉及到的锁。

当行被查询时的锁

一个查询可以直接通过SELECT查询数据,或者其它语句间接的查询数据,如:INSERT、MERGE、UPDATE和DELETE,其中只有INSERT操作不是必定会涉及到查询的。因为查询仅读数据,因此他们被其它DML语句干涉的可能性是最小的。

如果查询没有FOR UPDATE子句,则查询时:

1)查询不要求数据锁,因此,其它事务能查询和更新正在被查询的数据;

2)查询不必等待任何数据锁被释放,因此,查询总是能执行。一个例外是查询必须等待分布式事务的一些特定的数据锁。

当行被修改时的锁

一些数据库使用一个内存中的列表来维护锁,但Oracle数据库存储锁信息在数据块中,信息包含了被锁的行,每个行锁仅影响一行数据。

Oracle数据库为行锁的获取使用了一个队列机制,如果一个事务请求一个行锁,并且行未被锁,那么事务获取行的数据块的一个锁,事务自身会在数据块头的interested transaction list(ITL)区域放一个条目,被事务修改的每一行都指向ITL中存储的事务ID的一个拷贝,因此,被单个事务修改的在同一块中的100行数据会要求100个行锁,但是所有100行都引用同一个事务ID。

当事务结束时,事务ID保留在数据块头的ITL区域中。如果一个新的事物想修改一行,那么它使用事务ID判断该锁是否是激活的,如果锁是激活的,那么新事务的session会请求在锁被释放时被通知,否则,新事务获取锁。

INSERT、UPDATE、DELETE和SELECT ... FOR UPDATE将满足:

1)使用这些DML操作的事务将在修改的行上请求排它行锁,因此,其它事务不能更新或者删除锁定的行,直到事务commit或者roll back;

2)除了行锁,使用这些DML操作的事务至少需要请求一个子排它表锁(subexclusive table lock,SX)。如果事务已经拥有了一个S、SRX或者X表锁(比SX锁有更强的限制),那么SX锁不被需要;如果事务已经拥有了一个SS锁,那么Oracle数据库自动转换SS锁到SX锁;

3)除非涉及的行被修改,事务不会对任何子查询或者隐含的子查询涉及的行加行锁;例如下面的update操作,使用那个了一个子查询(括号中的部分)和隐含子查询(WHERE a > 5):

UPDATE t SET x = ( SELECT y FROM t2 WHERE t2.z = t.z ) WHERE a > 5;

事务将不会对子查询(SELECT y FROM t2 WHERE t2.z = t.z)涉及的行加锁。

4)在同一个事务中,一个查询能看到先前的DML语句修改的行,但不能看到其它事务未提交的改变。

时间: 2024-11-10 07:56:39

Oracle锁2:DML操作和锁的相关文章

Oracle ddl 和 dml 操作

  ddl 操作 窗口设置用户权限的方法  Oracle的数据类型  按住Ctrl点击表名 ,可以鼠标操作  插入的数据需要满足创建表的检查  主表clazz删除数据从表设置级联也会一同删除 有约束也强制删除 Oracle dml操作  简化分页查询 创建百万条记录的表 Oracle 数据库的备份 导入导出 原文地址:https://www.cnblogs.com/qingyundian/p/9142659.html

Oracle insert hang引发的行锁等待

问题描述: 客户方前台应用某个操作hang住,无报错也未有操作正常结束提示. 查看锁信息如下: SQL> with lk as (select blocking_instance||'.'||blocking_session blocker, inst_id||'.'||sid waiter 2              from gv$session 3              where blocking_instance is not null 4                and

Oracle 、MySql 数据库表被锁的原因分析

记录一次准备给客户预演示出现的问题 事故的背景: 当所以功能开发完成后,开发人员在本地进行了测视已经没问题了.就把所有开发的功能模块合并到 dev 分支,进行打包,发布到预演示的线上环境.当在给相关人员进行演示的时候,出现了问题. 我们使用 https 调用对方的接口发送 Json 数据,对方进行校验马上返回校验的响应结果.问题出现在我们每次发送数据都是成功的,但是对方发送回来的数据,一直不能正常插入 DB(使用的是 Oracle). 事故的真正原因: 因为有个同事在进行了 delete 后没有

oracle查看被锁的表和被锁的进程,杀掉进程

-- 1. 查看被锁的表 SELECT p.spid, a.serial#, c.object_name, b.session_id, b.oracle_username,b.os_user_name FROM v$process p, v$session a, v$locked_object b, all_objects c WHERE p.addr = a.paddr AND a.process = b.process AND c.object_id = b.object_id -- 2.

关于一个需求引发的事务操作和锁-记录解决过程和思路

参考资料: http://openwares.net/java/spring_mybatis_transaction.htmlspring,mybatis事务管理配置与@Transactional注解使用 http://www.cnblogs.com/mingxuan/archive/2011/10/11/2207560.html锁行还是锁表的实践验证 http://blog.csdn.net/hushanfeng110/article/details/50174787使用mybatis 实现乐

Oracle中查看表是否被锁和如何解锁的处理方法

--1.以下几个为相关表SELECT * FROM v$lock;SELECT * FROM v$sqlarea;SELECT * FROM v$session;SELECT * FROM v$process ;SELECT * FROM v$locked_object;SELECT * FROM all_objects;SELECT * FROM v$session_wait; --2.查看被锁的表 select b.owner,b.object_name,a.session_id,a.loc

如何在高并发环境下设计出无锁的数据库操作(Java版本) 转载

一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Java的Disruptor就是一个很好的例子.如果用java的concurrentCollection类去做,原理就是启动一个线程,跑一个Queue,并发的时候,任务压入Queue,线程轮训读取这个Queue,然后一个个顺序执行. 在这个设计模式下,任何并发都会变成了单线程操作,而且速度非常快.现在的n

阻塞与死锁(二)——各种操作对锁的申请

原文:阻塞与死锁(二)--各种操作对锁的申请 如何监视锁的申请.持有和释放: 在着手分析.处理阻塞.死锁之前,首先要进行"监控"和"信息收集" 1.检查一个连接当前所持有的锁: 可以使用sp_lock来查看所有连接持有的锁的内容. 在2005以后引入的DMV,还能用过sys.dm_tran_locks来查看: SELECT request_session_id, resource_type , resource_associated_entity_id , requ

oracle 查看锁表情况并处理锁表

/* *locked *query locked object and analyse reason,kill it * */ select 'alter system kill session ''' || SID || ',' || SERIAL# || ''';' from (select distinct a.sid, a.Serial#, status, machine, LOCKWAIT, logon_time from v$session a, v$locked_object b