用MySQL的默认隔离级别,可重复读,采用version=1,2,3,4.....来实现乐观锁的,当两个线程A,B同时操作数据库的一行记录,如果都是先开启事务,然后都是先查询出数据,比如说如下A,B来个线程查询结果如下:
Table :person
A:id   name   version
    1      tom         1 B:id   name   version
    1      tom         1  
此时A线程先开更新数据  
update set  name='jack'  ,version =version+1  where id=1 and version =1
然后A线程提交事务。
然后B线程也要更新name的值,但是此时的B线程在查询select *  from  person
得到的结果肯定是
B:id   name   version
    1      tom         1  此时如果B也要更新name的值,那么B线程要获取version的值是如何获取的呢,通过查询肯定不行,因为查询结果如上,那么是在java代码里面把每次更新过后的version值通过方法的参数传递给B线程吗。即我们在控制version都是通过java代码来获取version的值,而不是通过在数据库中查询相应的version值吗。在网上查的资料都是笼统的说,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,但是如何获取更新过后的version还是没有说明白。请教大神

解决方案 »

  1.   

    A和B线程同时获取到version为1的数据之后,A先提交了事务,修改了version,那么B那里就是旧的数据了,修改不成功才是乐观锁要做的事情,你这里如果需要B提交事务的时候更新version为2的数据,那么就不要加乐观锁了。
      

  2.   

      
    如果A提交了事务,B检索出的结果就不应该是这样,应该是version=2
    除非你的每个线程的检索结果都用了缓存,那么A提交事务的时侯就应该刷新缓存
    此时你只需判断B最开始取出来的version和A提交事务后再取出来的version是否一致,如果一致B就提交事务,否则做相应的排他处理,这就是所谓的乐观排他
      

  3.   

    乐观锁保证是的数据的一致性,意思就是当两个线程同时在操作一条数据的时候,A用户修改成功之后B用户提交事务是不会报错,但是不会修改A用户修改后的数据,如果B用户要继续修改,需要先重新获取最新的数据再修改。
      

  4.   


    我的问题是:如果B用户要继续修改,那怎么保证B重新获取的数据是最新的,就是实现方式。
    我的
    1.假设A,B用户在开启事务后,获取的数据是一致的,A先修改数据,然后提交事务。B在修改数据,那么就会报错,即修改不成功。
    2.那么我理解的B获取数据是最新的,是这样产生的,在A用户提交事务之后,B在开启事务,然后获取数据,这个数据应该是最新的。
    也就是A用户事务提交之后,B事务在开始,然后获取的数据就是最新的。
      

  5.   

    B事务在A提交事务后再重新取得一次数据(也就是B事务提交前再重新取一次数据)
    此时B重新取得的数据一定是最新的,除非你用了缓存,那你应该在提交事务时有个刷新缓存的操作
    或者你用个触发器来控制,在提交事务的时候比较version,不一致的是否就拒否
      

  6.   


    我的问题是:如果B用户要继续修改,那怎么保证B重新获取的数据是最新的,就是实现方式。
    我的
    1.假设A,B用户在开启事务后,获取的数据是一致的,A先修改数据,然后提交事务。B在修改数据,那么就会报错,即修改不成功。
    2.那么我理解的B获取数据是最新的,是这样产生的,在A用户提交事务之后,B在开启事务,然后获取数据,这个数据应该是最新的。
    也就是A用户事务提交之后,B事务在开始,然后获取的数据就是最新的。可以按照假设1来继续展开,如果B修改报错,重试,可以设定重试次数.具体可以参考:
    https://nanjiwubing123.iteye.com/blog/2261394
    在阿里JAVA开发手册中也有这样的约定:
    8. 【强制】并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用version作为更新依据。 说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。