数据库并发控制

事务相关概念

事务(Transaction)

对数据库一系列操作的集合。

事务的特性(ACID)

原子性(Atomicity):事务中的所有操作要么都执行完,要么一个都不执行。事务中的操作不可部分执行,更不可分割。

一致性(Consistency):事务运行结果不改变数据库中的数据一致性。例如“转账”事务,转账前后两个账户的余额总计是不变的。

隔离性(Isolation):事务并发运行过程中,一个事务不能被其他事务或操作干扰。同时执行的事务之间不能互相影响。

持久性(Durability):指事务运行完毕并成功提交后,其对数据库的所有操作结果应永久保留。以后运行的其他事务、操作甚至系统故障、意外情况等均不会影响该事务的运行结果,除非其他事务或操作更新相关数据。

调度(Schedule)

指事务的执行顺序。多个事务依次执行称为事务的串行调度(Serial Schedule);多个事务同时执行称为事务的并发调度(Concurrent Schedule)。多个事务并发调度的执行结果与它们串行调度的执行结果一致,则这个并发调度被称为“可串行化调度”(Serializable Schedule)。

冲突(Conflict)

如果事务调度中的两个操作交换执行顺序会改变它们所属的事务运行结果,则这两个操作冲突。

共有如下两种冲突情况:(1)同一事务的任何两个操作之间都是冲突的,无论这两个操作的数据对象是否相同,无论这两个操作是读还是写;(2)不同事务对同一数据对象,只要有任一操作涉及到写就一定冲突。

*

相关概念

谁来上锁?     

事务。(或者说,系统根据事务的需求来上锁)

锁谁?

数据对象,可以是单行记录、数据页、索引、表甚至整个数据库。

为啥要锁?

避免其他事务访问数据对象产生数据不一致性错误。

锁了会怎样?

数据对象被上锁后其他事务或操作就无法对该对象读或写,直到锁被释放。

锁多久?        

由事务决定。一般事务结束后会释放掉。

*粒度

*粒度即锁的对象或锁的作用范围。*粒度从高到低可分为数据库锁(Database-Level Lock)、表级锁(Table-Level Lock)、页级锁(Page Lock)、行级锁(Row Lock)以及索引(Index Key)等。

一般来说锁的粒度越高,事务执行效率更高,但并发性越低。假如某事务要处理数据库中的某些表,直接对整个数据库上锁无疑是最方便高效的方式,但这样其他事务对该数据库以及其中的所有表、行等均无法操作。如果该事务仅对它要操作的那些表逐一上锁,虽然效率较低,且需要同时管理多个锁,但其他事务可以并发处理同数据库中的其他表。

数据库软件一般支持不同粒度的锁并存。

锁的类型

共享锁(Shared Lock):简称S锁、读锁。事务A对某数据对象加了S锁,则事务A只能对该对象进行读操作。其他事务对于被上了S锁的对象只能上S锁或U锁,而不能上X锁。

排他锁(Exclusive Lock):简称X锁、写锁。在任一数据对象上,X锁均无法与其他任何锁共存。若某事务对数据对象加了X锁,则除该事务外任何事务无法对该数据对象进行读写操作。

提升锁(Update Lock):简称U锁。U锁是一种过渡锁。若事务A对某对象有修改意图,则先加上U锁。等到真正开始更新操作时再将U锁提升为X锁。被加了U锁的对象只能被别的事务加S锁。

意向锁(Intent Lock):简称I锁。

首先我们考虑以下这种情况:事务A在表1中上了一个行锁,此时事务B要对整个表1进行修改,此时B就要看表1是否上了锁,或者遍历表中所有的行,当表1没上锁或者表1中所有行都没上锁时B才能给表1上锁然后操作。但是遍历表中所有行效率太低。因此,A在上行锁之前先申请给该行所属的表1的I锁,上了I锁后再上行锁。当B看到表1上有意向锁就知道表被占用了,就不用再通过遍历表这种低效的方式找锁了。

意向锁一般与S锁或X锁连用,即意向共享锁(Intent Shared Lock,IS锁)意向排他锁(Intent Exclusive Lock,IX锁)。若某对象上存在IS锁或IX锁,说明该对象的下层某数据对象被加了S锁或X锁。同理,若某对象被加了S锁或X锁,则该对象的上级对象也要对应加上IS锁或IX锁。

 多粒度树

数据库并发控制

 如图,可以将不同粒度的上锁对象视为树型结构,从上到下分别是数据库、表、行。

上锁时可以仅针对某个节点单独加锁,同时这也意味着该节点下的所有子节点被加了相同的锁,且自该节点往上的所有祖节点被加上意向锁。

另外,为了减少冲突,加锁时应自上而下逐层加锁;解锁时应自下而上逐层解锁。

显示*与隐式*

显式*:直接加到数据对象上的*

隐式*:该数据对象没有独立加锁,但其某个祖节点加上了锁。

因此,在处理冲突时,系统不仅要检查显式*,还要检查隐式*。

*产生的问题

活锁(Live Lock):某事务一直在等待某个数据对象解锁而一直无法执行的情况称为活锁。例如事务A要对对象1上锁,但事务B提前上了锁,A只能等B解锁。但在B解锁后事务C、D、E......一直轮流使用对象1,不断上锁解锁,导致A一直无法给对象1上锁。

死锁(Dead Lock):系统中两个及以上的事务都在互相等待另一事务释放锁,导致这多个事务一直无法执行的状态。例如,事务A对对象1上锁,事务B对对象2上锁,但A也需要对2上锁,由于2被B占用,A只能等待,接着B要对对象1上锁,同样也要等待,就这样事务A、B互相等待对方解锁,导致两个事务一直无法执行。

隔离级别

(未完待续)

参考资料与部分图片出处

《数据库原理和实践教程》 袁晓洁 孙国荣

All about locking in SQL Server

mysql数据库意向锁意义 - 简书

数据库—*的粒度_Ge_zi327的博客-CSDN博客_*粒度

Multiple Granularity Locking in DBMS - GeeksforGeeks

mysql数据库意向锁意义 - 简书

上一篇:InnoDB存储引擎+[可重复读]事务隔离级别即可避免幻读的发生,不需[串行化]


下一篇:【Java并发】Java并发编程-02