修改死锁
This commit is contained in:
@@ -22,6 +22,8 @@ public class LocalRebillRequest implements Serializable
|
||||
private List<String> orderIdentifiers;
|
||||
private List<String> customerCodes;
|
||||
private List<String> productCodes;
|
||||
private List<Integer> orderStatuses;
|
||||
private List<Integer> billingFailStatuses;
|
||||
private String countryCode;
|
||||
private String creditArrearsStatus;
|
||||
private String beginBizDate;
|
||||
|
||||
+79
-3
@@ -12,6 +12,8 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -89,6 +91,8 @@ import com.bms.price.task.PrcCreditArrearsClearAsyncRunner;
|
||||
@Service
|
||||
public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(PrcOrderBillServiceImpl.class);
|
||||
|
||||
private static final String DICT_FEE_TYPE = "bms_fee_type";
|
||||
private static final String FEE_TYPE_REFUND = "REFUND";
|
||||
|
||||
@@ -701,8 +705,14 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
persistProductOrRedlineOnly(bill, result, productMode);
|
||||
}
|
||||
|
||||
private static final int LOCAL_REBILL_DB_RETRY_MAX = 3;
|
||||
private static final long LOCAL_REBILL_DB_RETRY_BASE_MS = 80L;
|
||||
|
||||
/**
|
||||
* Local rebill without outer txn: each {@link #bill} starts its own transaction so
|
||||
* MySQL deadlock can be retried cleanly (same idea as billing-task billWithDbRetry).
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult rebillLocalByBillId(String billId)
|
||||
{
|
||||
if (StringUtils.isEmpty(billId))
|
||||
@@ -723,8 +733,72 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
throw new ServiceException(MessageUtils.message("price.bill.bizDateRequired"));
|
||||
}
|
||||
TmsPriceBillRequest req = buildBillRequestFromBill(bill);
|
||||
// Full bill() path: AR guard, weight rules, quote, persist (local snapshot only).
|
||||
return self.bill(req);
|
||||
return billLocalWithDbRetry(billId.trim(), req);
|
||||
}
|
||||
|
||||
private TmsPriceQuoteResult billLocalWithDbRetry(String billId, TmsPriceBillRequest billReq)
|
||||
{
|
||||
RuntimeException last = null;
|
||||
for (int attempt = 1; attempt <= LOCAL_REBILL_DB_RETRY_MAX; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
return self.bill(billReq);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
last = e;
|
||||
if (attempt < LOCAL_REBILL_DB_RETRY_MAX && isRetryableDbConflict(e))
|
||||
{
|
||||
long sleepMs = LOCAL_REBILL_DB_RETRY_BASE_MS * attempt
|
||||
+ (long) (Math.random() * LOCAL_REBILL_DB_RETRY_BASE_MS);
|
||||
log.warn("local rebill db conflict, retry billId={} attempt={}/{} sleepMs={} msg={}",
|
||||
billId, Integer.valueOf(attempt), Integer.valueOf(LOCAL_REBILL_DB_RETRY_MAX),
|
||||
Long.valueOf(sleepMs), StringUtils.substring(e.getMessage(), 0, 200));
|
||||
try
|
||||
{
|
||||
Thread.sleep(sleepMs);
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
throw e;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
throw last != null ? last : new ServiceException("local rebill retry exhausted");
|
||||
}
|
||||
|
||||
/** Deadlock / lock wait — safe to retry whole bill txn (parallel local rebill). */
|
||||
private static boolean isRetryableDbConflict(Throwable e)
|
||||
{
|
||||
Throwable t = e;
|
||||
while (t != null)
|
||||
{
|
||||
String name = t.getClass().getName();
|
||||
if (name.indexOf("DeadlockLoser") >= 0
|
||||
|| name.indexOf("CannotAcquireLock") >= 0
|
||||
|| name.indexOf("MySQLTransactionRollback") >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String msg = t.getMessage();
|
||||
if (msg != null)
|
||||
{
|
||||
String m = msg.toLowerCase();
|
||||
if (m.indexOf("deadlock") >= 0
|
||||
|| m.indexOf("try restarting transaction") >= 0
|
||||
|| m.indexOf("lock wait timeout") >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
t = t.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -839,6 +913,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
query.setOrderIdentifiers(orderIdentifiers);
|
||||
query.setCustomerCodes(customerCodes);
|
||||
query.setProductCodes(productCodes);
|
||||
query.setOrderStatuses(request.getOrderStatuses());
|
||||
query.setBillingFailStatuses(request.getBillingFailStatuses());
|
||||
query.setCreditArrearsStatus(creditArrearsStatus);
|
||||
query.setCountryCode(countryCode);
|
||||
if (beginBizDate != null)
|
||||
|
||||
Reference in New Issue
Block a user