业务场景:
平台中有一个流水号功能,之前是采用乐观锁。使用乐观锁的问题是,当当前更新数据时,没有更新的时候,还是需要返回流水号。
这就不得不重新再获取,在平台的用户访问并发很大的时候,这个乐观锁会循环很多次,导致性能下降。
解决方法:
使用悲观锁,由数据库来锁定,当退出该方法时,数据库自动释放锁。
平台配置方法:
<tx:method name="genSequenceNo" propagation="REQUIRES_NEW" isolation="READ_COMMITTED" />
REQUIRES_NEW:
创建一个新事务,如果当前存在事务,将这个事务挂起。也就是说如果当前存在事务,那么将当前的事务挂起,并开启一个新事务去执行REQUIRES_NEW标志的方法。
先来总结一下结果:
1.标志REQUIRES_NEW会新开启事务,外层事务不会影响内部事务的提交/回滚
2.标志REQUIRES_NEW的内部事务的异常,会影响外部事务的回滚
测试方法使用多线程模拟实际环境:
package com.redxun.test.sys.manager; import java.util.List; import com.redxun.core.util.AppBeanUtil; import com.redxun.sys.core.manager.SysSeqIdManager; public class SysSeqNoThread implements Runnable { private List<String> list; public SysSeqNoThread(List<String> list){ this.list=list; } @Override public void run() { SysSeqIdManager mgr=AppBeanUtil.getBean(SysSeqIdManager.class); for(int i=0;i<1000;i++){ String no=mgr.genSequenceNo("ss", "1"); this.list.add(no); } } }
package com.redxun.test.sys.manager; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.junit.Test; import com.redxun.test.BaseTestCase; public class SysSeqIdTest extends BaseTestCase{ @Test public void getSeqNo() throws InterruptedException{ List<String> list = Collections.synchronizedList(new ArrayList<String>()); long start=System.currentTimeMillis(); Thread t1=new Thread(new SysSeqNoThread(list)); Thread t2=new Thread(new SysSeqNoThread(list)); t1.start(); t2.start(); t1.join(); t2.join(); System.err.println(list.size()); System.err.println(System.currentTimeMillis()-start); System.err.println("ok"); } }
测试了一下 产生2000个流水号,每个1.3毫秒,性能应该ok。