事务的并发控制
事务的并发控制
锁的机制就是来防止各个事务之间的相互影响,对并发访问进行控制,以保证数据一致性和完整性。当一个事务或操作企图防止另一个事务对其操作的对象产生影响时,该事务或操作就对该对象进行锁定,其他事务只能在该事务释放锁定之后才能操作该对象。
简单的锁类型有:排他锁(eXclusive Lock)、共享锁(Share Lock)
锁的易做图锁定协议
1、 一级锁定协议是指事务T在修改对象之前,必须先对该对象进行加X锁,并直到事务结束时才释放该X锁,如果事务T仅仅是读取对象就,则不需进行任何加锁。一级锁定协议避免了数据修改丢失,但是无法避免脏读、不可重复读。
2、 二级锁定协议是指在一级协议的基础上,加上事务T在读取对象之前必须加S锁,读完后立即释放S锁。二级锁定协议避免了数据修改丢失、脏读。但是避免不了不可重复读。
3、 易做图锁定协议是指在一级锁定协议的基础上,加上事务T在读取对象之间必须加S锁,直到事务结束后才释放S锁。易做图锁定协议避免了数据修改丢失、脏读、不可重复读。
活锁:指程序无限期等待。解决方法是先来先服务策略。
死锁:是指两个或多个事务都锁定了一些数据库对象,然后又需要锁定对方的数据库对象而且失败需要等待造成的。即相互等待对方锁定的资源释放。
预防死锁的方法有:一次锁定、顺序锁定(这是操作系统的解决方法,但不适用数据库)。
常用解决数据库死锁的方法是先诊断后解除。其方法有两种:超时法、等待图法。
超时法:即如果事务的等待时间超过了规定的时限,就认为发生了死锁。缺点是:容易误判死锁;时限不好决定;
等待图法:事务的等待图是一个有向图,如果事务T1等待事务T2,则T1和T2节点之间就有一条从T1指向T2的有向边。如果T1和T2之间产生回路就说明发生了死锁。
解决死锁的常用方法是:手动地选择一个处理死锁的代价最小的事务,将其撤销,使其释放所有已锁定的数据库对象。
锁定的粒度和意向锁
锁定对象的大小被称为锁定的粒度。
锁定的粒度越大,需要锁定的对象越少,可选择性越小、并发度越小、开销也越小。
锁定的粒度越小,需要锁定的对象就越多。可选择性也就越大、并发度也越多、开销也越大。
对一个节点加锁也就意味着对这个节点的各级子节点也加同样的锁。
意向锁:
指如果对一个节点加某种意向锁,则会对该节点的所有下级节点加这种锁(X锁、S锁); 如果对一个节点加某种锁(X锁、S锁),则必须先对该节点的所有上级节点加这种意向锁。
意向锁分三种:
1、 IS锁(Intended Share Lock即意向共享锁)
指:如果对一个节点加IS锁,则表示对它的所有下级节点有加S锁的意向;如果对一个节点加S锁,则必须先对该节点的各个上级节点加IS锁。
2、 IX锁(Intended eXclusive Lock即意向排他锁)
指:如果对一个节点加IX锁,则表示对它的所有下级节点有加X锁的意向;如果对一个节点加X锁,则必须先对该节点的各个上级节点加IX锁。
3、 SIX锁(Share Intented eXclusive Lock即共享意向排他锁)
指:如果对一个节点加SIX锁,则表示对它加S锁,然后再加IX锁,即SIX=S+IX。
ORACLE锁的分类
DDL锁(字典锁)、DML锁(数据锁)。
ORACLE锁的级别
数据库级别锁、表级别锁、行级别锁。不支持列级别锁。
锁定数据库的两种方式:
1、 将数据库设置成受限制方式;2、将数据库更改为只读方式;
设置为受限制方式就是禁止任何新的会话或新的事务。可以在SHUTDOWN数据库后,通过STARTUPRESTRICT命令来在启动数据库时设置为受限制方式,或通过ALTER SYSTEM ENABLE RESTRICTED SESSION 或 ALTER SYSTEM DISABLE RESTRICTED SESSION语句来在打开数据库的情况下启用或禁用数据库受限方式。已经连接的会话不受 ALTER SYSTEM ENABLE RESTRICTED SESSION语句的影响。
将数据库以只读方式打开 ALTER DATABASE OPEN READ ONLY;
表级别的锁:
当执行INSERT、UPDATE、DELETE、SELECT …FOR UPDATE 语句时都会自动在易做图作的表上加表级别的锁(TM类型的锁),当然也可以用LOCK TABLE语句手动设置一个表级别的锁。目的是防止对表结构进行修改操作。
行级别的锁:
当执行INSERT、UPDATE、DELETE、SELECT …FOR UPDATE 语句时都会自动在易做图作的表上加表级别的锁(TX类型的锁)。行级别的锁被用于在操作表中数据期间(在未提交或回退事务),防止其他用户对正在操作的行的数据进行修改操作。即行级别的锁按行来保护数据,防止并发访问相同的行。
注意:要想获得某个表上的TX锁,事务必须先获得该表上的TM锁。
锁的特点
ORACLE是通过队列机制来管理锁的。ORACLE中的锁是不受限制也不会自动升级的,这是和MSSQL中的不同之处。ORACLE中的查询语句是不会锁定数据的,前提是不带FOR UPDATE 子句的SELECT语句。因为ORACLE的查询是通过使用在撤销空间中所存储的数据被锁定之前的前映像来成功地执行的。这种方式提高了并发度,并保证了事务不会读取到脏数据。
锁的初始化参数:
1、DDL_WAIT_FOR_LOCKS:该参数是动态参数,用于控制DDL语句是否需要等待锁。默认是FALSE,表示不会等待锁(即NOWAIT方式)。当为TRUE时,表示会等待锁。使用
ALTER SESSION 或 ALTER SYSTEM语句更改该参数的值。
2、DDL_LOCKS:该参数是静态参数。用于指定DML锁的最大个数,取值范围是20到无限值。该参数默认值为TRANSACTIONS初始化参数的4倍,表示1个事务平均需要4个锁。使用
ALTERSYSTEM …SCOPE=SPFILE语句更改该参数的值,而且必须重新启动数据库。
4、 ENQUEUE_RESOURCES:该参数是静态参数。用于指定锁管理器可以并发锁定的资源数。使用 ALTER SYSTEM …SCOPE=SPFILE更改该参数,需要重启数据库。
5、 DISTRIBUTED_LOCK_TIMEOUT:该参数是静态参数。用于指定分布式事务等待锁定资源的总计时间,其单位是秒。默认为60秒。使用
ALTER SYSTEM …SCOPE=SPFILE更改该参数同样需要重启数据库。
解决锁争用的策略及方法:
1、 不应该运行上事务,在操作时应该及时地使用COMMIT和ROLLBACK语句。
2、 避免使用表锁,而是使用ORACLE默认的加锁机制。
3、 在更改数据之前,可以使用 SELECT … FOR UPDATE NOWAIT语句试探性的加锁,通过返回的提示了解具体情况,避免莫名的等待。
4、 非高峰时期使用DDL语句。
及时检测系统中是否存在锁,调查锁存在的原因,适当时机使用 ALTER SYSTEM KILL SESSION‘sid,serial#’杀死锁。