写读冲突 Write-Read Conflict : 读到一个未提交uncommitted的数据
数据库系统并发控制原理
被视为整体的一组工作
这组工作要么完全完成,要么全部不完成,不存在部分完成情况
真实生活中以转账说明事务:
第一步,从账户A中减去X元金额;
第二步,将X元金额存入账户B
这些多步操作必须全部完整完成,不能半途而废。数据库事务的工作方式与此相同。他们能保证,无论发生什么事情,数据的操作处理都被看成是原子的(你永远不会看到“转变一半”的情况)。
在并发访问数据库的情况下会发生什么问题
并发流程可能会改变隔离性和一致性这两个属性。让我们假设两个用户预订了一架飞机的同一个座位:
客户1 发现一个空座位
客户2 发现同样的空座位
客户1预订了这个座位
客户2也同时预订了这个座位
我们将事务的顺序执行称为schedule调度,它表示基于时间先后的一系列事务执行,在这里客户1和客户2分别存在两个事务,这个两个事务同时发生,我们需要通过串行化serializability来保证事务正确执行,也就是说,需要通过一个调度来实现并发控制机制。
一个调度包含下面一些操作:
read R(X)
write W(X)
commit (所有操作完成后,这些操作应该被确认和记录)
abort (在执行一部分操作后,如果我们退出,所有操作应该没有一个被确认完成或记录保存)
为了有完整的调度,commit 或abort是被强制的。
serial schedule 串行调度是事务执行时间没有交织,所有操作都是顺序执行。
当下面条件满足,Conflicting operation冲突操作会出现:
它们属于不同的事务
它们得访问同一的对象X
至少其中一个操作是W(X) (对X的写操作)
冲突操作
写读冲突 Write-Read Conflict : 读到一个未提交uncommitted的数据
读写冲突 Read-Write Conflict : 首次读以后,再读已经被修改的数据。
写写冲突 Write-Write Conflict :其中一个写操作丢失
Write-Read Conflict, 也称为reading uncommitted data读未提交的数据或脏都dirty-read,当一个事务T2试图读取数据库对象A,但是其已经被事务T1修改,还没有提交确认,当T1继续其事务时,对象A的数据已经不一致了,如下图:
换句话说,脏读是当一个事务读取了被另外一个事务修改但是还没有提交确认的表记录。
读写冲突Read-Write Conflict, 也称为unrepeatable reads, ,当一个事务T1读两次数据库对象A,第一读以后事务T1等待事务T2完成,T2覆盖重写了对象A,当T1再次读A时,A数据存在两个不同版本,T1被强迫退出,因为这是不可重复的读。
真实案例:Bob和Alice是票务员,他们要预订一个表演票,只剩余一张了,Alice登录进入,发现这周票比较贵,犹豫了一下,而Bob登录进入后,就立即买了这张票,然后退出。Alice决定买这张票时,发现已经没有多余的票了。
写写冲突Write-Write Conflict, 也称为覆盖未提交数据overwriting uncommitted data,它是发生在当有一个丢失修改情况下,试图使这种场景串行只能是下面两者之一:要么是事务T1版本,要么是事务T2的版本:
一旦并发事务应用到数据库上,使用调度确保串行化,也就是执行是顺序的,不会有时间的重叠,除了串行,还有以下几种调度方式:
ACA : 避免级联中断
可恢复性recoverable
严格调度strict schedule
总结:并发控制是通过串行化方式实现,这样能够确保任何非串行化的执行不会发生。当然主要问题是带来性能瓶颈。
后面会分享更多关于DBA内容,感兴趣的朋友可以关注下!
领取专属 10元无门槛券
私享最新 技术干货