乐观锁的实现,避免多线程丢失更新

rock912 发布于 2013/07/15 16:00
阅读 3K+
收藏 9

     今天看到一篇文章不错,和大家分享下

     “丢失更新”是一个很经典的问题。具体什么是“丢失更新”大家百度一下就知道了。

      预测我们的程序可能会出现 “丢失更新”问题。据我所知解决方法有两种(在隔离等级不为“可串行”的情况下):悲观锁、乐观锁。但同事认为update tablename set 字段1=字段1+1;这种类似的sql可以阻止“丢失更新”问题。我认为绝对不行(从隔离事物等级推断而出)。讨论无果,测试说话。

      经测试我的结论是正确的,呵呵。运行TestUpdateLost即可查看效果。

      此时数据的隔离等级,经SELECT @@tx_isolation;或者SELECT @@global.tx_isolation;查询都是REPEATABLE-READ

2.实验1

   目的:证明uppdate tablename set 字段1=字段1+1;这种类似的sql无法避免“丢失更新”。

   思路:启动N个多线程调用如下sql语句

Sql代码   收藏代码
  1. update  ACCOUNT set VERSION = VERSION+1 where ACC_ID = 1   

   如果最终VERSION中的值与线程个数N不相同,则任务无法避免。

   代码实现说明:这事情本和语言,框架无关,但我们总需要用具体代码实现一下。我用了java、ibatis。

2.1 主要代码

2.1.1 主要java代码

   TestUpdateLost片段1:

Java代码   收藏代码
  1. //经测试size=!VERSION(实际情况是VERSION=6096,size=10000),故而:update tablename set a=a+1;是不能阻止“丢失更新”的。  
  2.         int size=10000;  
  3.         for (int i = 1; i <=size; i++) {  
  4.             TestUpdateLost t = new TestUpdateLost();  
  5.             new Thread(t).start();  
  6.         }// end of for  
 

   TestUpdateLost片段2:

Java代码   收藏代码
  1. public void run() {  
  2.         try {  
  3.             Thread.sleep((int) (Math.random() * 1000));  
  4.             SimpleExample.updateVersionForUpdateLost(id);//执行sql语句  
  5.             System.out.println("-----------------"  
  6.                     + Thread.currentThread().getName()  
  7.                     + "-----------------------------------------" + count++);  
  8.         } catch (SQLException e) {  
  9.             e.printStackTrace();  
  10.         } catch (InterruptedException e) {  
  11.             e.printStackTrace();  
  12.         }  
  13.     }  
  

2.2 实验结果

     实验结果是数据库中VERSION=6096,此时线程个数为1w。故而:update tablename set a=a+1;这种类似的sql是不能阻止“丢失更新”的。

2.实验2-乐观锁的一种实现

    目的 :提供一种通过版本号递增的方式实现乐观锁

   思路:启动N个多线程调用如下sql语句

Sql代码   收藏代码
  1. update ACCOUNT set VERSION = VERSION+1 where ACC_ID = #id# AND VERSION=#version#  

   并通过如下java代码乱判断是否即将出现“丢失更新”:

Java代码   收藏代码
  1. /** 
  2.      * 更新版本,如果版本不一致则抛出乐观锁异常 
  3.      *  
  4.      * @param id 
  5.      * @throws SQLException 
  6.      * @throws SQLException 
  7.      */  
  8.     public static void updateVersionForOptimisticLock(int id,int version)  
  9.             throws OptimisticLockException, SQLException {  
  10.         Map<String, Integer> map=new HashMap<String, Integer>();  
  11.         map.put("id", id);  
  12.         map.put("version", version);  
  13.         final int count = sqlMapper  
  14.                 .update("updateVersionForOptimisticLock", map);  
  15.         if (count <= 0) {  
  16.             // throw new SQLException("乐观锁异常");  
  17.             throw new OptimisticLockException("乐观锁异常");//这里把javaee.jar包导入了  
  18.         }  
  19.   
  20.     }  


加载中
0
kentxp
kentxp
我对运行结果表是怀疑   我觉得可能部分线程运行时 由于数据库连接数或什么 异常了 造成更新数据不一致
0
lincolnpei
lincolnpei
表示怀疑,怎么就证明了乐观锁不能防止丢失更新呢?
返回顶部
顶部