酒店
This commit is contained in:
1 parent
47a4e4d7de
commit
d7a1c5c4e2
2 files changed
+62
-2
No files matched your search
+48
@@ -2855,9 +2855,40 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
|
||||
* <p>
|
||||
* 唯一键 uk_product_date=(tenant_id, product_id, stay_date) 不含 del_flag,必须物理删。
|
||||
* 删除区间须覆盖本次将写入的日期(含回调报文里的历史日),不能写死 LocalDate.now()。
|
||||
* <p>
|
||||
* 全量详情多酒店并行时,同租户唯一索引上易出现死锁,失败自动重试几次。
|
||||
*/
|
||||
private int persistDailies(SmHotelEntity hotel, List<DailyDraft> drafts, LocalDate fromInclusive,
|
||||
LocalDate toExclusive) {
|
||||
final int maxAttempts = 4;
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
return persistDailiesOnce(hotel, drafts, fromInclusive, toExclusive);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!isMysqlDeadlock(e) || attempt >= maxAttempts) {
|
||||
throw e instanceof RuntimeException ? (RuntimeException) e
|
||||
: new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
long sleepMs = 80L * attempt + (long) (Math.random() * 120);
|
||||
log.warn("|酒店日历落库|死锁重试|hotelId={}|code={}|attempt={}/{}|sleepMs={}|{}",
|
||||
hotel == null ? null : hotel.getId(),
|
||||
hotel == null ? null : hotel.getHotelCode(), attempt, maxAttempts, sleepMs,
|
||||
StrUtil.maxLength(e.getMessage(), 160));
|
||||
try {
|
||||
Thread.sleep(sleepMs);
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IllegalStateException("日历落库重试被中断", ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int persistDailiesOnce(SmHotelEntity hotel, List<DailyDraft> drafts, LocalDate fromInclusive,
|
||||
LocalDate toExclusive) {
|
||||
LocalDate delFrom = fromInclusive;
|
||||
LocalDate delTo = toExclusive;
|
||||
if (delFrom == null || delTo == null || !delFrom.isBefore(delTo)) {
|
||||
@@ -2933,6 +2964,23 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
|
||||
return toInsert.size();
|
||||
}
|
||||
|
||||
/** 并发拉详情时,日历表 uk_product_date 易出现 InnoDB 死锁 */
|
||||
private static boolean isMysqlDeadlock(Throwable e) {
|
||||
Throwable cur = e;
|
||||
while (cur != null) {
|
||||
String msg = cur.getMessage();
|
||||
if (msg != null && (msg.contains("Deadlock") || msg.contains("try restarting transaction"))) {
|
||||
return true;
|
||||
}
|
||||
String name = cur.getClass().getName();
|
||||
if (name.contains("MySQLTransactionRollbackException") || name.contains("DeadlockLoser")) {
|
||||
return true;
|
||||
}
|
||||
cur = cur.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<String, SmHotelRoomEntity> loadRoomMap(Long hotelId) {
|
||||
List<SmHotelRoomEntity> rows = roomMapper.selectList(Wrappers.<SmHotelRoomEntity>lambdaQuery()
|
||||
.eq(SmHotelRoomEntity::getHotelId, hotelId));
|
||||
|
||||
+14
-2
@@ -2023,8 +2023,20 @@ public class SmHotelSyncServiceImpl implements SmHotelSyncService {
|
||||
return;
|
||||
}
|
||||
String code = StrUtil.blankToDefault(h.getHotelCode(), String.valueOf(h.getId()));
|
||||
String name = StrUtil.blankToDefault(h.getHotelName(), "-");
|
||||
failLines.add(code + "|" + name + "|" + StrUtil.maxLength(StrUtil.blankToDefault(reason, "未知错误"), 300));
|
||||
String name = StrUtil.blankToDefault(h.getHotelName(), "-")
|
||||
.replace('|', '/')
|
||||
.replace('\r', ' ')
|
||||
.replace('\n', ' ');
|
||||
String raw = StrUtil.blankToDefault(reason, "未知错误");
|
||||
// MyBatis 堆栈含换行会把导出 Excel 拆成多行;死锁写成短文案便于重试
|
||||
String safe;
|
||||
if (raw.contains("Deadlock") || raw.contains("try restarting transaction")) {
|
||||
safe = "日历落库死锁(可点失败重试)";
|
||||
}
|
||||
else {
|
||||
safe = raw.replace('\r', ' ').replace('\n', ' ').replace('|', '/');
|
||||
}
|
||||
failLines.add(code + "|" + name + "|" + StrUtil.maxLength(safe, 300));
|
||||
}
|
||||
|
||||
private static void applyFailDetailOnly(SmHotelSyncLogEntity done, List<String> failLines, int fail) {
|
||||
|
||||
Reference in new issue
Block a user