Ø 数据库并发操带来的问题
数据的不一样,包括三类
² 丢失修改
当一个事务修改了数据,并且这种修改还没有还没有提交到数据库中时,另外一个事务又对同样的数据进 行了修改,并且把这种修改提交到了数据库中。这样,数据库中没有出现第一个事务修改数据的结果,好像这种 数据修改丢失了一样。
² 脏读
当一个事务正在访问数据,并对数据进行了修改,而这种修改还没有提交到数据库中,这时,另一个事务 也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另一个事务读到的这个数据是 脏数据,依据脏数据所做的操作可能是不正确的。
² 不可重复读
在一个事务内,多次读同一数据。在这个事务还没有结束时,另一个事务也访问该同一数据,那么,在第 一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能是不一样的。
Ø 如何解决?
避免不一致性的方法和技术就是并发控制。最常用的并发控制技术是封锁技术。
² 并发控制原因
数据库是共享资源,通常有许多个事务同时在运行。
当多个事务并发地存取数据库时就会产生同时读取和 /或修改同一数据的情况。若对并发操作不加控制就可能会 存取和存储不正确的数据,破坏数据库的一致性。所以数据库管理系统必须提供并发控制机制。
解决方法
² 禁止数据出现不一致--封锁技术
l 何为封锁
封锁就是事务 T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就 对该数据对象有了一定的控制,在事务T释放它的锁之前,其他的事务不能更新此数据对象。封锁是实现并发控 制 的一个非常重要的技术。
l 封锁的类型
1、 排它锁(Exclusive Locks,简称X锁)
2、 共享锁(Share Locks,简称S锁)。
n 排它锁
排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加 任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。
n 共享锁
共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S 锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
² 数据可以不一致,但是数据更新要进行一致性检查
1) 从数据库中读出一批初始数据,依据这些数据做了一系列的操作,当把操作结果更新到数据库 时,先检查数据库中那“同一批”初始数据是否已经发生了变化,如果发生了变化,根据业务需要,进行一定 的处理。这种方式并发性强,比较灵活,而且是不加锁的,这就避免了不少麻烦问题,实现起来要简单一些。
2) 简单考虑,检查数据一致性时,可以检查数据库中数据和内存中数据的值是否相同。但如果数 据量较大,这种检查恐怕效率很低。其实一致性检查要考虑粒度问题,根据实际情况选择合适的粒度。检查具 体数据的值是否变化,可以说是最细的粒度。可以通过数据的版本控制来实现更粗粒度的检查。以数据记录为 单位进行版本管理,可以在数据表中加一个整型字段作为版本。当insert一条数据时,设置一个初始版本值。 当update数据时,先检查数据库中的版本值是否发生了变化,如果没有变化才执行update,并将被更新的数据 版本值加1。根据业务逻辑,有时要把一组数据使用一个版本来管理(更粗的粒度),这可以使用一个专门存储 版本的表来实现。要注意的是,一致性检查和数据更新一定要在同一个系统事务中进行,才能保证一致性。
3) 这种方式同时也存在一定的问题,那就是其发现问题的滞后性,通常是在提交之后才报出相应 的错误,之前是不会报出的,这样导致用户之间所做的工作可能都是无用工,一个缓解的办法是,除了在最后提 交时检查一致性外,可以在业务事务进行过程中,时不时的就检查一下,越早发现不一致就可以越早的处理。这 也只是缓解,不能从根本上解决。
Ø 总结
事物都存在两个方面,有利有弊,数据的并发控制有利的一方面是:数据库是共享资源,通常有许多个事务 同时在运行;不利的一方面就是其带来的问题。在正确性和并发性之间权衡一下,这两方面有时是矛盾的,没法得 到完美的解决,两者之间只能达到一个平衡,任何绝对都不是最好的,看用户对那个方面更需要一些。