Hibernate托管实体ID相同状态不一致问题排查求助
同一事务内Hibernate托管实体ID相同但状态不一致问题
问题背景
我们在AWS托管的EC2英特尔实例上遇到了异常数据行为:存在ID相同但状态不同的Hibernate托管实体,该问题本地无法复现,仅能通过日志确认。
实体类定义
class History { private Enum status; @OneToMany(mappedBy = HistoryEntry_.HISTORY) @OrderBy("id ASC") @BatchSize(size = 10) private List<HistoryEntry> entries = new LinkedList<>(); } // 关联系统的两个部分 class HistoryEntry { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "history_id", updatable = false, nullable = false) private History history; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "process_id", updatable = false, nullable = false) private ProcessInfo processInfo; } class ProcessInfo { @OneToMany(mappedBy = HistoryEntry_.PROCESS_INFO) // 仅用于事务内的确定性排序 @OrderBy("id ASC") @BatchSize(size = 10) private List<HistoryEntry> entries = new LinkedList<>(); }
初始数据状态
History history1 = new History(Status.PENDING); ProcessInfo processInfo1 = new ProcessInfo(); ProcessInfo processInfo2 = new ProcessInfo(); HistoryEntry entryA = new HistoryEntry(history, processInfo1); HistoryEntry entryB = new HistoryEntry(history, processInfo1);
- 状态为
PENDING的history1包含条目列表[A, B] processInfo1包含条目列表[A, B]processInfo2无条目
事务内操作流程
操作全程在单个事务内执行
// 返回包含A、B两个条目的列表 List<HistoryEntry> entries = historyEntryRepo.findAllByProcessInfoAndNotArchived(processInfo1); // 基于ID比较,得到仅包含history1的集合 Set<History> histories = entries.stream() .map(HistoryEntry::getHistory) .toSet(); // 预期仅包含一个元素 if(histories.size() > 1){ throw new IllegalStateException(); } History history1 = histories.iterator().next(); entityManager.lock(history1, LockModeType.OPTIMISTIC_FORCE_INCREMENT); HistoryEntry entryC = new HistoryEntry(); entryC.setHistory(history1); history1.getEntries().add(entryC); history1.status = Status.COMPLETED; entryC.setProcessInfo(processInfo2); processInfo2.getEntries().add(entryC); historyEntryRepo.save(entryC);
数据不一致问题
在同一事务内验证各History实体状态:
Set<History> histories1 = processInfo1.getEntries().stream() .map(HistoryEntry::getHistory) .toSet(); Set<History> histories2 = processInfo2.getEntries().stream() .map(HistoryEntry::getHistory) .toSet();
两者均返回单个结果history1,但状态字段值不一致:
History(id=1, status=PENDING)不符合预期History(id=1, status=COMPLETED)
临时修复方式
通过重新从仓库查询可恢复数据一致性:
historyEntryRepo.findAllByProcessInfo(processInfo1).stream() .map(HistoryEntry::getHistory) .toSet(); historyEntryRepo.findAllByProcessInfo(processInfo2).stream() .map(HistoryEntry::getHistory) .toSet();
此时结果一致且符合预期:History(id=1, status=COMPLETED)
疑问
该问题是否由缓存问题或缓存失效异常导致?
内容的提问来源于stack exchange,提问作者hotzen
相关产品推荐
相关产品推荐

