乐观锁导致并发失败解决方案

业务场景

用户在使用支付宝或者微信给商户付款时,支付成功回调之后,需要修改商户的余额,并产生流水。由于存在多个用户在同一商户付款的并发情况,采用@version乐观锁来防止商户余额信息错乱,但在并发的情况下,乐观锁只能保证数据不错乱,并不能保证业务的正常进行,因为用户已经支付成功,不能因为乐观锁产生流水失败或者计算余额失败而告知用户支付失败,这个时候需要解决并发情况也能顺利产生流水和修改余额。

解决方案一

在乐观锁的基础上配合同步锁synchronized,同步锁的详细功能请查阅他人写的博客,如http://blog.csdn.net/luoweifu/article/details/46613015
伪代码如下:

//因为多个站的并发不受影响,所以只需要考虑多个用户在同一用户的同步锁就ok
//选取油站的id作为同步锁的条件,并选用字符串的intern()方法
synchronized (merchant.getId().intern()){
    //产生流水
    //修改该商户的余额
}

关于intern()方法,是类控制的一个String池,如果池中有该String,则返回该String,如果没有,则在池中创建该String并返回,详细介绍见源码。

    /**
     * Returns a canonical representation for the string object.
     * 

* A pool of strings, initially empty, is maintained privately by the * class {@code String}. *

* When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. *

* It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. *

* All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * The Java™ Language Specification. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */ public native String intern();

解决方案二

将修改余额与生成流水写在同一事务内,一旦发生异常,利用事务回滚,再次重新运行整个事务,直到运行成功。由于我采用的是方案一,所以方案一不详谈。查资料的时候有多个博客有介绍,
如:https://gist.github.com/crazycode/4970741,
也有说用AOP的,http://blog.csdn.net/zhanghongzheng3213/article/details/50819539

你可能感兴趣的:(Java,Web开发,J2EE)