事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
并发是指多个事务同时执行,这会带来一些问题。
丢失修改由两次事务的修改导致,比如事务 T1
修改 A
,同时事务 T2
也修改 A
,那么最后 A
的值将由事务 T2
的修改结果决定,这样事务 T1
的修改就没了,导致丢失修改。
分为两种情况,第一种是事务 T1
读取 K
,这个时候读取到一个值 A
,然后事务 T2
增加或者删除了一条记录,过了一会事务 T1
又过来读取了这个 A
,发现值不见了,或者多了一些值,很迷幻,所以叫幻读。
第二种情况就是前面相同,但是事务 T2
修改了刚才读取的那个值 A
,导致事务 T1
再过来读的时候发现值不一样了,这叫做不可重复读。
事务 T1
修改了 A 的值,但是还没有提交,这个时候被事务 T2
读取了 A
的值,但是过了一会事务 T1
由于某些原因回滚了操作,所以 T2
读取到的值就是错的,这就是 脏读。
两类锁分别是 排它锁 X
和 共享锁 S
。
在 T
给数据 A
加上排它锁之后,就只有 T
才能读和修改 A
,同时其他事务就不能再加任何锁了,直到 T
释放排它锁。
在 T
给数据 A
加上共享锁之后,T
只能读 A
,不能修改,其他事务可以在它的基础上加共享锁,但是不能加排它锁,也就是说其他的事务只能读不能修改,直到 T
释放共享锁为止。
封锁协议规定了使用锁对数据对象加锁时需要遵循的规则。
一级封锁协议
它规定事务在修改数据之前必须加排它锁,直到事务结束才释放。
这就解决了丢失修改的问题,因为事务在修改数据的时候要加 X
锁,之后其它事务就不能再加锁了,也就是不能修改了,必须等第一个事务修改完成之后才能再加锁然后修改。
但是读数据的时候是不用加锁的,那就解决不了其它的问题。
二级封锁协议
它规定事务在读取事务之前必须加共享锁,而 读取结束就释放 。
注意这里是读完了就可以释放锁了,还是不太行,但是可以解决脏读的问题:比如事务 T1
在修改数据的时候加了 X
锁,这个时候事务 T2
要想再读取就要加 S
锁,但是在 X
锁释放之前是不能加其他锁的,所以必须等待事务 T1
释放锁,这个时候无论他是提交事务还是回滚都不会影响到 T2
读取的数据正确性了。
但是他不能不解决可重复读的问题。
三级封锁协议
它规定事务在读取事务之前必须加共享锁,直到 事务结束 才释放。
这就解决了不可重复度的问题,因为当事务 T1
读取数据对象的时候,加了 S
锁,其他的事务想修改该数据对象,必须加 X
锁,但是在 S
锁之上是不能加 X
锁的,只能等到 T1
释放 S
锁,而释放的时候事务 T1
也结束了。