Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockManager.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockManager.java (.../OptimisticLockManager.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockManager.java (.../OptimisticLockManager.java) (revision 23797) @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -15,6 +16,8 @@ import com.forgon.system.concurrent.model.OptimisticLock; import com.forgon.system.transaction.model.TransactionInfo; +import edu.emory.mathcs.backport.java.util.Collections; + /** * @author dandan 2018年7月16日 上午11:07:47 * @@ -43,9 +46,14 @@ throwException("参数非法!"); } EntityLocksInfo entityLocksInfo = entityToLocksMap.get(entity); - if(entityLocksInfo == null){ - entityLocksInfo = entityToLocksMap.putIfAbsent(entity, new EntityLocksInfo(entity)); + EntityLocksInfo newEntityLocksInfo = new EntityLocksInfo(entity); + if (entityLocksInfo == null) { + entityLocksInfo = entityToLocksMap.putIfAbsent(entity, + newEntityLocksInfo); } + if (entityLocksInfo == null) { + entityLocksInfo = newEntityLocksInfo; + } entityLocksInfo.requestLockById(id); } @@ -133,4 +141,18 @@ public void releaseAllLocks() { } + + // 主要用于测试和界面显示 + public List getAllLocks() { + List locks = new LinkedList(); + Collection entityLocksInfos = entityToLocksMap + .values(); + if (entityLocksInfos != null) { + for (EntityLocksInfo entityLocksInfo : entityLocksInfos) { + locks.addAll(entityLocksInfo.getAllLocks()); + } + } + Collections.sort(locks, OptimisticLock.ID_COMPARATOR); + return locks; + } } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockException.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockException.java (.../OptimisticLockException.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockException.java (.../OptimisticLockException.java) (revision 23797) @@ -9,7 +9,9 @@ */ public class OptimisticLockException extends RuntimeException { + private static final String OPTIMISTICLOCKEXCEPTIONPREFIX = "乐观锁:"; + public OptimisticLockException(String message) { - super(message); + super(OPTIMISTICLOCKEXCEPTIONPREFIX + message); } } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3Impl.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3Impl.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3Impl.java (revision 23797) @@ -0,0 +1,14 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +/** + * @author dandan 2018年7月21日 下午4:51:11 + * + */ +public class OptimisticLockManagerTestLevel3Impl extends + OptimisticLockManagerTestImpl implements + OptimisticLockManagerTestLevel3 { + +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1Impl.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1Impl.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1Impl.java (revision 23797) @@ -0,0 +1,90 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +import static org.testng.Assert.assertEquals; + +import java.util.Collection; +import java.util.List; + +import com.forgon.system.concurrent.model.OptimisticLock; + +import edu.emory.mathcs.backport.java.util.Collections; + +/** + * @author dandan 2018年7月21日 下午4:49:11 + * + */ +public class OptimisticLockManagerTestLevel1Impl extends + OptimisticLockManagerTestImpl implements + OptimisticLockManagerTestLevel1 { + + private OptimisticLockManagerTestLevel2 optimisticLockManagerTestLevel2 = null; + + public void setOptimisticLockManagerTestLevel2( + OptimisticLockManagerTestLevel2 optimisticLockManagerTestLevel2) { + this.optimisticLockManagerTestLevel2 = optimisticLockManagerTestLevel2; + } + + public void test_OneTransaction_RepeatRequest(String entity, String id, + WaitObject notifyObject, WaitObject continueObject) { + { + requestLockById(entity, id, notifyObject, continueObject); + List allLocks = optimisticLockManager.getAllLocks(); + assertEquals(allLocks.size(), 1); + OptimisticLock optimisticLock = allLocks.get(0); + assertEquals(optimisticLock.getEntity(), entity); + assertEquals(optimisticLock.getId(), id); + } + + { + requestLockById(entity, id, notifyObject, continueObject); + requestLockById(entity, id, notifyObject, continueObject); + List allLocks = optimisticLockManager.getAllLocks(); + assertEquals(allLocks.size(), 1); + OptimisticLock optimisticLock = allLocks.get(0); + assertEquals(optimisticLock.getEntity(), entity); + assertEquals(optimisticLock.getId(), id); + } + } + + public void test_requestLockByStringIds_OneTransaction_RepeatRequest(String entity, List ids,WaitObject notifyObject,WaitObject continueObject){ + { + requestLockByStringIds(entity, ids, notifyObject, continueObject); + List allLocks = optimisticLockManager.getAllLocks(); + Collections.sort(allLocks,OptimisticLock.ID_COMPARATOR); + assertEquals(allLocks.size(), ids.size()); + + for(int i=0;i allLocks = optimisticLockManager.getAllLocks(); + Collections.sort(allLocks,OptimisticLock.ID_COMPARATOR); + assertEquals(allLocks.size(), ids.size()); + + for(int i=0;i ids, WaitObject notifyObject, + WaitObject continueObject) { + requestLockByStringIds(entity, ids, notifyObject, continueObject); + } +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTest.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTest.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTest.java (revision 23797) @@ -0,0 +1,47 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +import java.util.Collection; + +/** + * @author dandan 2018年7月21日 下午4:59:36 + * + */ +public interface OptimisticLockManagerTest { + + public static final String ENTITY_OPTIMISTICLOCKTEST = "OptimisticLockTest"; + + public void requestLockById(String entity, String id, + WaitObject notifyObject, WaitObject continueObject); + + public void requestLockByStringIds(String entity, Collection ids, + WaitObject notifyObject, WaitObject continueObject); + + public static class WaitObject { + private volatile boolean done = false; + + public boolean isDone() { + return done; + } + + public void setDone() { + this.done = true; + } + + public void setDone(boolean done) { + this.done = done; + } + + public void waitForDone() { + while (!done) { + try { + Thread.sleep(1 * 100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLock.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLock.java (.../OptimisticLock.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLock.java (.../OptimisticLock.java) (revision 23797) @@ -3,6 +3,7 @@ */ package com.forgon.system.concurrent.model; +import java.util.Comparator; import java.util.Date; import com.forgon.system.transaction.model.TransactionInfo; @@ -88,4 +89,21 @@ this.requestTime = requestTime; } + public static final Comparator ID_COMPARATOR = new Comparator() { + @Override + public int compare(OptimisticLock o1, OptimisticLock o2) { + String s1 = o1.getId(); + String s2 = o2.getId(); + if (s1 == null && s2 == null) { + return 0; + } else if (s1 == null) { + return -1; + } else if (s2 == null) { + return 1; + } else { + return s1.compareTo(s2); + } + } + }; + } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2Impl.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2Impl.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2Impl.java (revision 23797) @@ -0,0 +1,21 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +/** + * @author dandan 2018年7月21日 下午4:50:57 + * + */ +public class OptimisticLockManagerTestLevel2Impl extends + OptimisticLockManagerTestImpl implements + OptimisticLockManagerTestLevel2 { + + private OptimisticLockManagerTestLevel3 optimisticLockManagerTestLevel3 = null; + + public void setOptimisticLockManagerTestLevel3( + OptimisticLockManagerTestLevel3 optimisticLockManagerTestLevel3) { + this.optimisticLockManagerTestLevel3 = optimisticLockManagerTestLevel3; + } + +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel1.java (revision 23797) @@ -0,0 +1,21 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +import java.util.Collection; +import java.util.List; + +/** + * @author dandan 2018年7月21日 下午4:48:52 + * + */ +public interface OptimisticLockManagerTestLevel1 extends + OptimisticLockManagerTest { + + public void test_OneTransaction_RepeatRequest(String entity, String id,WaitObject notifyObject,WaitObject continueObject); + public void test_requestLockByStringIds_OneTransaction_RepeatRequest(String entity, List ids,WaitObject notifyObject,WaitObject continueObject); + + public void requestLockById_TRANS_NEVER(String entity, String id,WaitObject notifyObject,WaitObject continueObject); + public void requestLockByStringIds_TRANS_NEVER(String entity, Collection ids,WaitObject notifyObject,WaitObject continueObject); +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockNoTransactionException.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockNoTransactionException.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockNoTransactionException.java (revision 23797) @@ -0,0 +1,15 @@ +/** + * + */ +package com.forgon.system.concurrent.model; + +/** + * @author dandan 2018年7月23日 下午3:29:22 + * + */ +public class OptimisticLockNoTransactionException extends + OptimisticLockException { + public OptimisticLockNoTransactionException() { + super("requestLockById调用异常,当前上下文不存在事务!"); + } +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/model/EntityLocksInfo.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/model/EntityLocksInfo.java (.../EntityLocksInfo.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/model/EntityLocksInfo.java (.../EntityLocksInfo.java) (revision 23797) @@ -3,6 +3,7 @@ */ package com.forgon.system.concurrent.model; +import java.util.Collection; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -35,13 +36,12 @@ // return false; // } public void requestLockById(String id) { - OptimisticLock existingOptimisticLock = idToLockMap.get(id); TransactionInfo transactionInfo = TransactionUtils .currentTransactionInfo(); if (transactionInfo == null) { - // TODO log - return; + throw new OptimisticLockNoTransactionException(); } + OptimisticLock existingOptimisticLock = idToLockMap.get(id); if (existingOptimisticLock == null) { OptimisticLock newOptimisticLock = new OptimisticLock(); newOptimisticLock.setEntity(entity); @@ -50,14 +50,17 @@ existingOptimisticLock = idToLockMap.putIfAbsent(id, newOptimisticLock); + + if (existingOptimisticLock == null) { + transactionInfo.addLock(newOptimisticLock); + } } if (existingOptimisticLock != null) { if (existingOptimisticLock.getTransactionInfo() != transactionInfo) { - throw new OptimisticLockException(String.format( - "id为%s的记录已被事务%s锁定,请稍后重试!", id, - transactionInfo.getJoinpointIdentification())); + throw new OptimisticLockConflictException(id, transactionInfo); } } + } public void releaseTransactionLocks(TransactionInfo transactionInfo) { @@ -82,4 +85,7 @@ this.entity = entity; } + public Collection getAllLocks() { + return idToLockMap.values(); + } } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestImpl.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestImpl.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestImpl.java (revision 23797) @@ -0,0 +1,51 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +import java.util.Collection; + +import com.forgon.system.concurrent.service.OptimisticLockManager; + +/** + * @author dandan 2018年7月21日 下午5:01:50 + * + */ +public abstract class OptimisticLockManagerTestImpl implements + OptimisticLockManagerTest { + + protected OptimisticLockManager optimisticLockManager; + + public void setOptimisticLockManager( + OptimisticLockManager optimisticLockManager) { + this.optimisticLockManager = optimisticLockManager; + } + + public void requestLockById(String entity, String id, + WaitObject notifyObject, WaitObject continueObject) { + optimisticLockManager.requestLockById(entity, id); + notifyCaller(notifyObject); + waitForDone(continueObject); + } + + public void requestLockByStringIds(String entity, Collection ids, + WaitObject notifyObject, WaitObject continueObject) { + for (String id : ids) { + requestLockById(entity, id, null, null); + } + notifyCaller(notifyObject); + waitForDone(continueObject); + } + + private void notifyCaller(WaitObject notifyObject) { + if (notifyObject != null) { + notifyObject.setDone(); + } + } + + private void waitForDone(WaitObject waitObject) { + if (waitObject != null) { + waitObject.waitForDone(); + } + } +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel2.java (revision 23797) @@ -0,0 +1,13 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +/** + * @author dandan 2018年7月21日 下午4:50:25 + * + */ +public interface OptimisticLockManagerTestLevel2 extends + OptimisticLockManagerTest { + +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockInterceptor.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockInterceptor.java (.../OptimisticLockInterceptor.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockInterceptor.java (.../OptimisticLockInterceptor.java) (revision 23797) @@ -17,6 +17,13 @@ */ public class OptimisticLockInterceptor implements MethodInterceptor { + private OptimisticLockManager optimisticLockManager; + + public void setOptimisticLockManager( + OptimisticLockManager optimisticLockManager) { + this.optimisticLockManager = optimisticLockManager; + } + /* * (non-Javadoc) * @@ -39,7 +46,7 @@ try { TransactionSynchronizationManager .registerSynchronization(new OptimisticLockTransactionSynchronizationAdapter( - transactionInfo)); + optimisticLockManager, transactionInfo)); } catch (Exception e) { e.printStackTrace(); } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockTransactionSynchronizationAdapter.java =================================================================== diff -u -r23785 -r23797 --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockTransactionSynchronizationAdapter.java (.../OptimisticLockTransactionSynchronizationAdapter.java) (revision 23785) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/OptimisticLockTransactionSynchronizationAdapter.java (.../OptimisticLockTransactionSynchronizationAdapter.java) (revision 23797) @@ -15,16 +15,19 @@ TransactionSynchronizationAdapter { private TransactionInfo transactionInfo = null; - + private OptimisticLockManager optimisticLockManager; + public OptimisticLockTransactionSynchronizationAdapter( + OptimisticLockManager optimisticLockManager, TransactionInfo transactionInfo) { super(); this.transactionInfo = transactionInfo; + this.optimisticLockManager = optimisticLockManager; } @Override public void afterCompletion(int status) { // 事务完成时,清除事务相关的锁 - + optimisticLockManager.releaseTransactionLocks(transactionInfo); } } Index: forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockConflictException.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockConflictException.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/model/OptimisticLockConflictException.java (revision 23797) @@ -0,0 +1,18 @@ +/** + * + */ +package com.forgon.system.concurrent.model; + +import com.forgon.system.transaction.model.TransactionInfo; + +/** + * @author dandan 2018年7月23日 下午4:40:05 + * + */ +public class OptimisticLockConflictException extends OptimisticLockException { + public OptimisticLockConflictException(String id, + TransactionInfo transactionInfo) { + super(String.format("id为%s的记录已被事务%s锁定,请稍后重试!", id, + transactionInfo.getJoinpointIdentification())); + } +} Index: forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3.java =================================================================== diff -u --- forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3.java (revision 0) +++ forgon-tools/src/main/java/com/forgon/system/concurrent/service/test/OptimisticLockManagerTestLevel3.java (revision 23797) @@ -0,0 +1,13 @@ +/** + * + */ +package com.forgon.system.concurrent.service.test; + +/** + * @author dandan 2018年7月21日 下午4:50:36 + * + */ +public interface OptimisticLockManagerTestLevel3 extends + OptimisticLockManagerTest { + +}