锁的基本原理

oracle032



锁的基本原理

1、Oracle锁类型

锁的作用:保护数据,没有锁就没有并发,锁是用来限制并发的

数据库反应慢不一定是数据负严重,也可能是锁的原因阻止了事务的进行:开两个客户端修改数据会明显发现第二个会很慢就是因为第一个用户锁住了行记录

latch锁:chain,链(server Pro 并发访问时就通过获取latch锁来进行保护链)

LOCK锁:buffer 、数据块、数据行

排他锁(X):就是A访问加锁X而B就不能访问加锁了

共享锁(S):就是A、B都可以加相同的共享S锁

2、行级锁:DML语句;是LOCK锁的最小粒度锁;oracle特有也最影响并发的效率的

事务锁TX:一个事务一个事务锁,是因为行级锁产生的

锁的结构

事务锁的加锁和解锁过程:DML语句(加锁);commit/rollback(解锁)

只有排他锁(行级锁和事务锁都是排他锁的类型)

不影响读(CR块)

3、表级锁:TM

行级排他锁(Row exclusive)RX锁

当我们进行DML时,会自动在被更新的表上添加RX锁,可以执行LOCK命令显式的在表上添加RX锁

允许其他事务通过DML语句修改相同表里的其他数据行

允许使用lock命令对表添加RX锁定

不允许其他事务对表添加X锁

行级共享锁(Row Shared,简称RS锁)

select … from for update

是会产生一个事务,和普通DML语句一样产生行级锁,并在表级别加了一个RS锁没加RX锁;但实际并没有修改数据

共享锁(Share,简称S锁)

通过lock table in share mode命令添加该S锁

排他锁(Exclusive,简称X锁):对表的结构进行改变,和表的删除;其他用户不能进行任何操作

通过lock table in exclusive mode命令添加X锁

共享行级排他锁(Share Row Exclusive,简称SRX锁)

通过lock table in share row exclusive mode命令添加SRX锁

lock table  in [row share][row exclusive][share][share row exclusive][exclusive] mode;

研究锁侧重于两点:锁的兼容性,锁的产生原因

4、锁的兼容性

5、加锁语句以及锁的释放

6、锁相关视图

v$transaction

XIDUSN表示当前事务使用的回滚段的编号

XIDSLOT说明该事务在回滚段头部的事务表中对应的记录编号(也可以叫做槽号)

XIDSQN说明序列号

STATUS说明该事务是否为活动的

v$lock

记录了session已经获得的锁定以及正在请求的锁定的信息

SID说明session的ID号

TYPE说明锁定锁定级别,主要关注TX和TM

LMODE说明已经获得的锁定的模式,以数字编码表示

REQUEST说明正在请求的锁定的模式,以数字编码表示

BLOCK说明是否阻止了其他用户获得锁定,大于0说明是,等于0说明否

锁定模式          锁定简称     编码数值

Row Exclusive          RX           3

Row Shared           RS          2

Share                S           4

Exclusive           X           6

Share Row Exclusive      SRX           5

NULL                 N/A           0或者1

v$enqueue_lock

该视图中包含的字段以及字段含义与v$lock中的字段一模一样。

只不过该视图中只显示那些申请锁定,但是无法获得锁定的session信息。

其中的记录按照申请锁定的时间先后顺序排列,先申请锁定的session排在前面,排在前面的session将会先获得锁定。

v$locked_object

记录了当前已经被锁定的对象的信息

XIDUSN表示当前事务使用的回滚段的编号

XIDSLOT说明该事务在回滚段头部的事务表中对应的记录编号

XIDSQN说明序列号

OBJECT_ID说明当前被锁定的对象的ID号,可以根据该ID号到dba_objects里查找被锁定的对象名称

LOCKED_MODE说明锁定模式的数字编码

v$session

记录了当前session的相关信息

SID表示session的编号

SERIAL#表示序列号

SID和SERIAL#可以认为是v$session的主键,它们共同唯一标识一个session

测试锁:

开启3个session:

SQL>  select sid from v$mystat where rownum=1;

SID

----------

29

SQL>

SQL>  select sid from v$mystat where rownum=1;

SID

----------

35

SQL>

SQL>  select sid from v$mystat where rownum=1;

SID

----------

38

SQL>

使用sessionID为29进行更新t表操作

SQL>  update t set name=‘qq‘ where id = 2;

1 row updated.

SQL>

查询事务: select xidusn,xidslot,xidsqn,status from v$transaction;

5     30     1099     ACTIVE

说明当前存在一个活动的事务

下面是查询sessionID为29的连接所产生的事务信息:

select sid,type,id1,id2,

decode(lmode,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘) lock_mode,

decode(request,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘)

request_mode,block

from v$lock

where sid=29;

SID, TYPE, ID1, ID2, LOCK_MODE, REQUEST_MODE, BLOCK

29     AE     100     0     Share     None     0

29     TM     74585     0     Row Exclusive     None     0//表级锁

29     TX     327710     1099     Exclusive     None     0//行级锁

SID表示sessionID,TYPE表示锁的类型,ID2表示事务槽被覆盖的次数,ID1中的信息包含两种信息:1.事务表  2.事务表中行

通过:

将ID1拆解

select trunc(327710/power(2,16)) as undo_blk#,bitand(327710,to_number(‘ffff‘,‘xxxx‘)) + 0 as slot#

from dual;

UNDO_BLK#, SLOT#

5     30//显示的是该事务的信息,这也说明了ID1表示了两种信息的说法。

LOCK_MODE表示锁的模式,REQUEST_MODE是否请求锁,BLOCK表示锁住哪个事务

select OWNER,OBJECT_NAME,OBJECT_ID,OBJECT_TYPE,CREATED,LAST_DDL_TIME,STATUS,NAMESPACE from dba_objects where object_id=74585;//被锁的对象

OWNER, OBJECT_NAME, OBJECT_ID, OBJECT_TYPE, CREATED, LAST_DDL_TIME,    STATUS, NAMESPACE

SYS     T            74585     TABLE     22-12月-14     04-1月 -15     VALID     1

对于TM锁来说,ID1表示被锁定的对象的对象ID,ID2始终为0

对于TX锁来说,ID1表示事务使用的回滚段编号以及在事务表中对应的记录编号,ID2表示该记录编号被重用的次数(wrap)

使用sessionID为35进行更新t表操作:

SQL> update t set name=‘ww‘ where id = 2;

//没有执行结果说明被锁住了

下面是查询sessionID为29、35的连接所产生的事务信息:

select sid,type,id1,id2,

decode(lmode,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘) lock_mode,

decode(request,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘)

request_mode,block

from v$lock

where sid in(29,35)

order by sid;

SID, TYPE, ID1, ID2, LOCK_MODE, REQUEST_MODE, BLOCK

29     TM     74585     0     Row Exclusive     None     0

29     AE     100     0     Share     None     0

29     TX     327710     1099     Exclusive     None     1//锁住了一个事务

35     TM     74585     0     Row Exclusive     None     0

35     AE     100     0     Share     None     0

35     TX     327710     1099     None     Exclusive     0//请求一个排他锁,因为上面的29锁住了

使用sessionID为38进行更新t表操作:

SQL> update t set name=‘ww‘ where id = 2;

//没有执行结果说明被锁住了

查询v$enqueue_lock来获得锁定队列中的session信息:

select sid,type,

decode(request,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘)

request_mode

from v$enqueue_lock

where sid in(35,38);

SID, TYPE, REQUEST_MODE

35     AE     None

38     AE     None

35     TX     Exclusive

38     TX     Exclusive

可以知道sessionID为35,38的连接需要锁为X锁

查询几个锁之间的关系:

select a.sid blocker_sid,a.serial#,a.username as blocker_username,b.type,

decode(b.lmode,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘) lock_mode,

b.ctime as time_held,c.sid as waiter_sid,

decode(c.request,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘) request_mode,

c.ctime time_waited

from   v$lock b, v$enqueue_lock c, v$session a

where  a.sid = b.sid and    b.id1= c.id1(+) and b.id2 = c.id2(+) and c.type(+) = ‘TX‘ and  b.type = ‘TX‘ and  b.block   = 1

order by time_held, time_waited;

BLOCKER_SID, SERIAL#, BLOCKER_USERNAME, TYPE, LOCK_MODE, TIME_HELD, WAITER_SID, REQUEST_MODE, TIME_WAITED

29     557               SYS     TX     Exclusive     2452     38          Exclusive     274

29     557               SYS     TX     Exclusive     2452     35          Exclusive     712

BLOCKER_SID:锁的sessionID为29,BLOCKER_USERNAME:锁的用户名是sys,

TYPE:锁的类型为TX(行级锁)LOCK_MODE:锁的模型为排他锁,TIME_HELD:锁所持续的时间

WAITER_SID:该锁被哪个sessionID锁等待,REQUEST_MODE:请求锁的类型,TIME_WAITED:请求时间

通过上面的信息就可以知道某个连接所持有的锁时间,假如时间过长说明该连接存在问题,就可以杀掉该连接

alter system kill session ‘29,557‘;//第一个参数BLOCKER_SID,第二个为SERIAL#参数

一个事务修改多行,产生一个TX锁

select sid from v$mystat where rownum=1;

SQL> update t set name=‘rr‘ where id=2;

1 row updated.

SQL> update t set name=‘rr‘ where id=2;

1 row updated.

SQL> update t set name=‘rr‘ where id=2;

1 row updated.

SQL>

select sid,type,id1,id2,

decode(lmode,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘) lock_mode,

decode(request,0,‘None‘,1,‘Null‘,2,‘Row share‘,3,‘Row Exclusive‘,4,‘Share‘,5,‘Share Row Exclusive‘,6,‘Exclusive‘)request_mode,block

from v$lock

where sid=38;

SID, TYPE, ID1, ID2, LOCK_MODE, REQUEST_MODE, BLOCK

38     AE     100     0     Share     None     0

38     TM     74585     0     Row Exclusive     None     0

38     TX     327680     1099     Exclusive     None     0

可以获得的TX锁定的总个数由初始化参数transactions决定,而可以获得的TM锁定的个数则由初始化参数dml_locks决定:

select name,value from v$parameter where name in(‘transactions‘,‘dml_locks‘);

NAME, VALUE

dml_locks     1084

transactions     271

查询资源的使用情况:

select resource_name as "R_N",current_utilization as "C_U",max_utilization as "M_U",initial_allocation as "I_U"

from v$resource_limit

where resource_name in(‘transactions‘,‘dml_locks‘);

R_N,     C_U,  M_U,        I_U

dml_locks     1     1           1084

transactions     1     1            271

通过上面的参数可以知道dml_locks资源当前使用了1个而且最多的时候也只使用了1个,最大的资源数为1084

transactions同上,通过这个可以判断资源设置是否合理,假如M_U的值等于或者接近于I_U时说明需要增大I_U值因为:

可以获得的TX锁定的总个数由初始化参数transactions决定,而可以获得的TM锁定的个数则由初始化参数dml_locks决定

grant select on v_$mystat to hr;

死锁

两个session(以A和C来表示),如果A持有C正在申请的锁定,同时C也持有A正在申请的锁定时,这时发生死锁现象。死锁是典型的“双输”情况,如果任其发展,则会出现A和C这两个session正在执行的事务都无法结束的现象。因此,在Oracle数据库中,造成死锁的那个DML语句会被撤销。死锁总是由于应用程序设计不合理引起的。

当某个session的事务引起了死锁时,Oracle会自动将阻塞该事务的其他事务中相应的DML语句撤销,而阻塞该事务的其他事务中的其他DML语句并没有撤销。

session 1

select sid from v$mystat where rownum=1;

update employees set last_name=last_name||‘a‘

where employee_id=100

session 2

select sid from v$mystat where rownum=1;

update employees set last_name=last_name||‘b‘

where employee_id=101;

session 1

update employees set last_name=last_name||‘c‘ where employee_id=101;

session 2

update employees set last_name=last_name||‘d‘ where employee_id=100;

对HR用户进行解锁和密码设置:

SQL>  select username,password,account_status from dba_users where username=‘HR‘;

USERNAME                       PASSWORD

------------------------------ ------------------------------

ACCOUNT_STATUS

--------------------------------

HR

EXPIRED & LOCKED//过期且被锁住的状态

SQL> alter user hr account unlock;

User altered.

SQL>  select username,password,account_status from dba_users where username=‘HR‘;

USERNAME                       PASSWORD

------------------------------ ------------------------------

ACCOUNT_STATUS

--------------------------------

HR

EXPIRED//此时hr只是过期并没有被锁住

SQL> alter user hr identified hr;

alter user hr identified hr

*

ERROR at line 1:

ORA-00924: missing BY keyword

SQL>  alter user hr identified by hr;

User altered.

SQL>  select username,password,account_status from dba_users where username=‘HR‘;

USERNAME                       PASSWORD

------------------------------ ------------------------------

ACCOUNT_STATUS

--------------------------------

HR

OPEN//打开状态

SQL>

时间: 2024-11-08 20:10:52

锁的基本原理的相关文章

数据库锁的基本原理

数据库锁的基本原理 为了保证数据的完事性和一致性,数据库系统采用锁来实现事务的隔离性.各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别. 从并发事务锁定的关系上看,可以分为共享锁定和独占锁定.从锁定的对象不同,一般可以分为表锁定和行锁定. 锁 共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它. 独占锁也叫排他锁,适用于修改数据的场合.它所锁定的资源,其他事务不能读取也不能修改. 当一个事务访问某种数据库资源时,如果执行select语句,

Curator实现zookeeper分布式锁的基本原理

一.写在前面 之前写过一篇文章(<拜托,面试请不要再问我Redis分布式锁的实现原理>),给大家说了一下Redisson这个开源框架是如何实现Redis分布式锁原理的,这篇文章再给大家聊一下ZooKeeper实现分布式锁的原理. 同理,我是直接基于比较常用的Curator这个开源框架,聊一下这个框架对ZooKeeper(以下简称zk)分布式锁的实现. 一般除了大公司是自行封装分布式锁框架之外,建议大家用这些开源框架封装好的分布式锁实现,这是一个比较快捷省事儿的方式. 二.ZooKeeper分布

数据库 锁机制

锁的基本原理 为了保证数据的完事性和一致性,数据库系统采用锁来实现事务的隔离性.各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别. 从并发事务锁定的关系上看,可以分为共享锁定和独占锁定.从锁定的对象不同,一般可以分为表锁定和行锁定. 锁 共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它. 独占锁也叫排他锁,适用于修改数据的场合.它所锁定的资源,其他事务不能读取也不能修改. 当一个事务访问某种数据库资源时,如果执行select语句,必须先

[转载] 数据库分析手记 —— InnoDB锁机制分析

作者:倪煜 InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工作机制.通过本文可以帮助大家了解InnoDB锁的基本原理,常见的冲突.死锁,以及对InnoDB事务日志信息的解读. 1. 索引基本原理 InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果MySQL的执行计划没有用到索引,那么行锁也就无意义了,所以了解锁之前需要了

InnoDB锁机制分析

InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工作机制.通过本文可以帮助大家了解InnoDB锁的基本原理,常见的冲突.死锁,以及对InnoDB事务日志信息的解读. 1. 索引基本原理 InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果MySQL的执行计划没有用到索引,那么行锁也就无意义了,所以了解锁之前需要了解一点索引原

并发编程实践四:实现正确和高效的锁

你是否觉得锁是一种很神奇的东西,在并发编程中,你只需要将你的代码加上锁,就能保证代码是线程安全的(当然现实和感觉有很大差别,代码的线程安全是非常复杂的),那么,这些都是怎么做到的呢?当存在大量线程同时竞争锁时,竞争失败的锁会怎么做呢?锁又是怎么保证这一切高效的执行的呢?这篇文章将为你回答这些问题,首先我将介绍怎样实现一个正确的锁,然后介绍高效的锁应该具备的条件,最后将介绍两种常用的队列锁算法:CLH锁和MCS锁. 文中将用到一些原子变量的特性,你可以将原子变量看作加强版的volatile变量,具

基于Redis的简单分布式锁的原理

参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的加锁机制.但是到了分布式环境,单机环境中的锁就没什么作用了,因为每个节点只能获取到自己机器内存中的锁,而无法获取到其他节点的锁状态. 分布式环境中,应该用专门的分布式锁来解决需要加锁的问题.分布式锁有很多实现,Redis,zookeeper都可以.这里以Redis为例,讲述一下基于Redis的分布式

聊聊高并发(十六)实现一个简单的可重入锁

可重入锁指的是如果一个线程已经获得了一个锁,那么它可以多次进入这个锁,当然前提是线程需要先获得这个锁. 可重入锁是最常使用的锁,Java的内置锁就是可重入锁,使用synchronized关键字可以启用内置锁机制,比如说一个类有两个synchronized方法A和B,在A方法中调用了B方法,如果锁不是可重入的,那么访问B时需要再次竞争锁,这样会带来死锁. public synchronized void A(){ B(); } public synchronized void B(){ } 可重入

mysql死锁(锁与事务)

线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来也无太大影响,但还是需要解决,保不齐哪天成为性能瓶颈.     为了更系统的分析问题,本文将从死锁检测.索引隔离级别与锁的关系.死锁成因.问题定位这五个方面来展开讨论. 1 死锁是怎么被发现的? 1.1 死锁成因&&检测方法 左图那两辆车造成死锁了吗?不是!右图四辆车造成死锁了吗?是! 我们m