来自:http://www.blogjava.net/super2/archive/2008/11/01/237994.html
离线并发的来源
在Web项目中,离线并发显得尤其严重。例如,用户A和用户B同时修改数据库中的某张表的R行,加入R行有两个字段分别是C1,C2。
假如按照如下过程修改:
1 用户A将数据R(C1,C2)读取到A的浏览器中。
2 用户B将数据R(C1,C2)读取到B的浏览器中。
3 用户A在浏览器上将数据修改为R(C1’,C2),同时更新到数据库。
4 用户B在浏览器上将数据修改为R(C1,C2’),同时更新到数据库。
上述过程存在两个问题,第一,第4步B在修改数据的时候数据库中的数据和B的浏览器中数据已经不一致了;第二,如果程序按照哪个字段变化在数据库中更新哪个字段的方式处理的话,那么经过上述四步修改,数据库中R行的内容是(C1’,C2’),这和A或者B的想法都不同(A认为是(C1’,C2),B认为是(C1,C2’))。
上述过程中A对数据库的修改过程或者B对数据库的修改过程,都是无法根据数据库的最新内容做修改,所以成为离线。A和B同时对记录R进行就该叫离线。
以上的环境叫离线并发。
那么如何解决离线并发过程中遇到的问题呢?我们引入锁机制。
锁机制
锁机制,就是在需要修改的数据上加互斥锁,通过互斥锁避免数据被同时修改。锁机制更具其应用环境又分为乐观锁和悲观锁
乐观锁
乐观锁,指认为冲突很少发生,所以只是在数据修改的时候比较修改的基础数据和数据库中的数据是否相同,相同则修改,否则提示用户重新装入数据库中已经变化的数据。
实现方法1:在进行update的时候使用where条件,在Where标间中比较所有上一步中查询得到的数据。如果数据库中的数据没有变化,则update可以更新到内容,否则update语句不能更新到内容,可以根据update的返回值确定更新是否成功。
实现方法2:在每一个表中追加一个特殊字段,类型为timestamp,每次更新的时候比较这个字段的值是否一致,如果一致,则更新,同时将这个字段更新为当前时间,否则,说明数据已经变更。这也可以使用update加上where实现。
悲观锁
悲观锁指,需要修改的数据,在读取的时候就对数据加锁,其他用户在准备修改,读取数据的阶段判断数据是否上锁,以此来决定是否进行修改前的读操作。
实现方法:
通常在数据库中建立一张lock表,该表的字段包括,表明,唯一索引,时间,用户信息等。
在用户读取数据准备修改的时候,首先判断lock表中是否存在自己将要读取的数据。
如果不存在,则在lock表中添加一条记录,记录对那张表的哪行数据进行修改;如果存在,在判断时间字段是否超时。
如果超时,则更新lock表中本条记录的时间字段。(防止死锁的必要手段)
如果存在,也不超时,说明本条记录正在被其他用户修改,则返回并发信息。