Przeglądaj źródła

解决 saveOrUpdate接口并发报错

JiahengHe 2 lat temu
rodzic
commit
a799e121af

+ 5 - 0
pom.xml

@@ -79,6 +79,11 @@
       <artifactId>fst</artifactId>
       <version>2.50</version>
     </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>31.1-jre</version>
+    </dependency>
   </dependencies>
 
   <build>

+ 16 - 11
src/main/java/common/utils/model/SaveUtil.java

@@ -1,6 +1,8 @@
 package common.utils.model;
 
 import com.alibaba.druid.util.StringUtils;
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
 import com.jfinal.plugin.activerecord.Db;
 import com.jfinal.plugin.activerecord.Model;
 
@@ -9,19 +11,22 @@ import java.util.concurrent.atomic.AtomicInteger;
 public class SaveUtil {
 	public static final int SAVE_CODE = 1;
 	public static final int UPDATE_CODE = 2;
+	Interner<String> pool = Interners.newWeakInterner();
 	
-	public static int saveOrUpdate(Model<?> model) {
+	public int saveOrUpdate(Model<?> model) {
 		if(!StringUtils.isEmpty(model.getStr("chainId")) && !StringUtils.isEmpty(model.getStr("hash"))){
 			model.set("id", model.getStr("chainId").concat(model.getStr("hash")));
 		}
 //		Object[] values = CopyUtil.generateDuplicateObjects(model._getAttrValues());
-		// 是否存在
-		if (Db.template("hasRecord", TableUtil.getTableName(model), model.getStr("chainId"), model.getStr("hash")).queryInt() == 1){
-			model.update();
-			return UPDATE_CODE;
-		} else {
-			model.save();
-			return SAVE_CODE;
+		synchronized (pool.intern(model.get("id"))){
+			// 是否存在
+			if (Db.template("hasRecord", TableUtil.getTableName(model), model.getStr("chainId"), model.getStr("hash")).queryInt() == 1){
+				model.update();
+				return UPDATE_CODE;
+			} else {
+				model.save();
+				return SAVE_CODE;
+			}
 		}
 	}
 
@@ -40,15 +45,15 @@ public class SaveUtil {
 		}
 	}
 	
-	public static int saveSuperAndSub(Model<?> superModel, Model<?> subModel) {
+	public int saveSuperAndSub(Model<?> superModel, Model<?> subModel) {
 		AtomicInteger code = new AtomicInteger();
 
 		Db.tx(() -> {
 			subModel.set("id", subModel.getStr("chainId").concat(subModel.getStr("hash")));
 			superModel.set("id", superModel.getStr("chainId").concat(superModel.getStr("hash")));
-			SaveUtil.saveOrUpdate(superModel);
+			saveOrUpdate(superModel);
 
-			code.set(SaveUtil.saveOrUpdate(subModel));
+			code.set(saveOrUpdate(subModel));
 
 			return true;
 		});

+ 1 - 1
src/main/java/modules/address/AddressController.java

@@ -44,7 +44,7 @@ public class AddressController extends MyController {
 
 		if (service.isAddressExist(address)) {
 			service.update(address);
-			renderJson(MyRet.ok("Save address successful.").setData(address));
+			renderJson(MyRet.ok("Update address successful.").setData(address));
 		} else {
 			service.append(address);
 			renderJson(MyRet.ok("Append address ok.").setData(address));

+ 4 - 2
src/main/java/modules/address/AddressService.java

@@ -27,6 +27,8 @@ public class AddressService {
 	private V3LpService v3LpService;
 	@Inject
 	private TokenService tokenService;
+	@Inject
+	private SaveUtil saveUtil;
 
 	public boolean append(Address address) {
 		address.setId(address.getChainId()+address.getHash());
@@ -51,11 +53,11 @@ public class AddressService {
 	}
 	
 	public int saveOrUpdateBySubModel(Model<?> subModel, Address address) {
-		return SaveUtil.saveSuperAndSub(address, subModel);
+		return saveUtil.saveSuperAndSub(address, subModel);
 	}
 	
 	public int appendOrUpdate(Address address) {
-		return SaveUtil.saveOrUpdate(address);
+		return saveUtil.saveOrUpdate(address);
 	}
 
 

+ 5 - 1
src/main/java/modules/chain/ChainService.java

@@ -1,5 +1,6 @@
 package modules.chain;
 
+import com.jfinal.aop.Inject;
 import com.jfinal.plugin.activerecord.Db;
 import com.jfinal.plugin.activerecord.Record;
 import common.model.Address;
@@ -10,6 +11,9 @@ import common.utils.model.SaveUtil;
 import java.util.List;
 
 public class ChainService {
+	@Inject
+	private SaveUtil saveUtil;
+
 	public boolean isChainExists(Chain chain) {
 		return Db.template("chain.hasChain", chain.getId()).queryInt() == 1;
 	}
@@ -23,7 +27,7 @@ public class ChainService {
 	}
 
 	public int appendOrUpdate(Chain chain) {
-		return SaveUtil.saveOrUpdate(chain);
+		return saveUtil.saveOrUpdate(chain);
 	}
 
 	public int deleteByChainId(int chainId){

+ 4 - 2
src/main/java/modules/tx/TxService.java

@@ -34,6 +34,8 @@ public class TxService {
 	private PendingService pendingService;
 	@Inject
 	private AddressService addressService;
+	@Inject
+	private SaveUtil saveUtil;
 	
 	static String[] TX_CONDITION_KEYS = {"block", "hash", "from", "to"};
 	static String[] TRANSFER_CONDITION_KEYS = {"from", "to", "token"};
@@ -65,7 +67,7 @@ public class TxService {
 	}
 
 	public int appendOrUpdate(Tx tx) {
-		return SaveUtil.saveOrUpdate(tx);
+		return saveUtil.saveOrUpdate(tx);
 	}
 
 	public int saveBatch(Model<? extends Model<?>> subModel, Tx tx, List<? extends Model<?>> transferList) {
@@ -92,7 +94,7 @@ public class TxService {
 		AtomicInteger code = new AtomicInteger();
 
 		Db.tx(() -> {
-			code.set(SaveUtil.saveOrUpdate(subModel));
+			code.set(saveUtil.saveOrUpdate(subModel));
 			return true;
 		});
 

+ 1 - 1
src/test/http/ChainTest.http

@@ -5,7 +5,7 @@ Content-Type: application/json
 {
   "id": 41089,
   "chain": "Ethereum",
-  "tokenSymbol": "ETH",
+  "tokenSymbol": "ETH2",
   "networkName": "Ethereum Network",
   "http": "https://mainnet.infura.io/v3",
   "explorer": "https://etherscan.io",

+ 1 - 1
src/test/http/address/AddressTest.http

@@ -33,7 +33,7 @@ Content-Type: application/json
 {
   "chainId": 10001,
   "hash": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
-  "name": "TestAddress2",
+  "name": "TestAddress",
   "auth": {
     "auth": "9d8b7074bf189dcad17189c8f264c0cb",
     "timestamp": "123123"

+ 1 - 1
src/test/http/address/BalLpTest.http

@@ -9,7 +9,7 @@ Content-Type: application/json
   "factory": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "fee": 3000,
   "positionId": 1,
-  "name": "测试BalLp",
+  "name": "123测试BalLp",
   "valueStr": "10000",
   "isStable": 0,
   "functionStr": "functionStrSample",

+ 1 - 1
src/test/http/address/FactoryTest.http

@@ -5,7 +5,7 @@ Content-Type: application/json
 {
   "chainId": 1,
   "hash": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
-  "name": "测试1",
+  "name": "123测试1",
   "router": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "positionManager": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "fee": 3000,

+ 1 - 1
src/test/http/address/TokenTest.http

@@ -6,7 +6,7 @@ Content-Type: application/json
   "chainId": 1,
   "hash": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "decimals": 18,
-  "name": "测试1",
+  "name": "123测试1",
   "symbol": "TestToken",
   "totalAmountStr": "100000",
   "totalValueStr": "30000",

+ 1 - 1
src/test/http/address/V2LpTest.http

@@ -9,7 +9,7 @@ Content-Type: application/json
   "factory": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "fee": 3000,
   "positionId": 1,
-  "name": "测试V2Lp",
+  "name": "123测试V2Lp",
   "token0": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "token1": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "r0Str": "10000",

+ 1 - 1
src/test/http/address/V3LpTest.http

@@ -9,7 +9,7 @@ Content-Type: application/json
   "factory": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "fee": 3000,
   "positionId": 1,
-  "name": "测试V3Lp",
+  "name": "213测试V3Lp",
   "token0": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "token1": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "r0Str": "10000",

+ 1 - 1
src/test/http/tx/HistoryTest.http

@@ -22,7 +22,7 @@ Content-Type: application/json
   "fromAddress": "0x13fbc25180fa1dc051838a2744e41c3f5a651b19", 
   "toAddress": "0x036b758df82270534096ea1d0b321981788779d7", 
   "inputData": "0x760f93ae00000000000000000000000000000000000000000000000a96bb748bbc498000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000008a521189bfedf99b1dc84bc21571cf8b799dbd4d0000000000000000000000005186c4fb5752eb4a952c7ef03fae3e543f48383e", 
-  "valueStr": 123,
+  "valueStr": 121123,
   "nonce": 42707, 
   "method": "0x760f93ae", 
   "transactionType": "0x0", 

+ 2 - 2
src/test/http/tx/PendingTest.http

@@ -108,8 +108,8 @@ Content-Type: application/json
   "blockNumber": 123,
   "fromAddress": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
   "toAddress": "0x8A9009847570FdbCc676c7fD547aB26A358a5005",
-  "method": "method2",
-  "status": "status3",
+  "method": "method12",
+  "status": "status23",
   "transactionIndex": 0,
   "nonce": 0,
   "gasPriceStr": "13333",