事务是并发控制的基本单位。并发是指多个事务同时执行,这样就有可能破坏事务的ACID特性,DBMS的并发控制技术就是对并发操作进行正确调度以保证事务的隔离性和一致性。
举个列子,A,B同时买票:二者同时读到票共16张,A买了票,票减一为15;B买了票,但由于先前读的票数是16,再执行票减一为15。
实质上这样A进行的操作就被覆盖了,与实际不符。
上面数据不一致的原因主要在于并发操作破坏了数据的隔离性,并发控制就是要用正确的方式调度并发操作,保证事务隔离性从而保证一致性,主要是通过封锁技术。
封锁
封锁是指某事务处理某数据时进行加锁,在该事务未释放锁时其他事务不可对该数据进行更新。
基本封锁类型有:
排他锁(X/写锁):事务加上X锁后未释放任何事务不可再加锁。
共享锁(S/读锁):事务加上S锁后未释放其他事务最多只能加S锁。
以上两种锁可以保证隔离性,但也会引发一些问题,比如活锁和死锁。
活锁是指一个事务对一个数据的封锁申请一直在等待(因为其他事务也在申请),这只需要按先来先服务的策略即可。
死锁就比较麻烦,产生死锁的原因是多个事务都已经封锁了一些数据对象,然后又同时请求为其他事务封锁的数据对象加锁,从而出现死等待。这样问题一般通过预防或者解除等操作解决。预防一般有一次封锁法和顺序封锁法,实际上,数据库用的更多是诊断和解除的操作。诊断有超时法(通过设定时间判断)和等待图法(通过回路判断),解除代价最小的是撤销。
并发调度的可串行性
我们会有疑问:
什么样的并发调度是正确的?
可串行化的调度是正确的。
什么样的调度又是可串行化的调度呢?
充分条件是指其可冲突可串行化调度。
那什么是冲突可串行化调度?
首先明白,冲突操作是指不同事务对同一个数据的读写和写写操作,如果一个调度在保证冲突操作次序不变的条件下交换两个事务的不冲突操作得另一个调度,若得的调度结果一致,认为其为冲突可串行化调度,该调度也是可串行化调度。
介绍完了这些,可以了解通过在加锁上面加一些封锁协议,可以保证可串行化调度,比如两段锁协议(选均加锁,再均解锁),不过注意,这也是充分条件。