Thực thể ngủ đông mà tôi đang lưu trong cơ sở dữ liệu (Oracle) có quan hệ rất phức tạp, theo nghĩa là nó có nhiều thực thể liên quan. Nó trông giống như thế này ...StaleStateException khi lưu thực thể với quan hệ phức tạp
@Table(name = "t_HOP_CommonContract")
public class Contract {
@Id
private ContractPK id;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private ContractGroupMember contractGroupMember;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "TransactionId", referencedColumnName = "TransactionId"),
@JoinColumn(name = "PrimaryContractId", referencedColumnName = "PrimaryContractId")
})
@Fetch(FetchMode.SUBSELECT)
private List<ContractLink> contractLinks;
// . . . . . . .
// A couple of more one to many relationships
// Entity getters etc.
}
Tôi cũng có một vài đơn vị hơn như ...
@Table(name = "t_HOP_TRS")
public class TotalReturnSwap {
@Id
private ContractPK id;
// Entity Getters etc.
}
Bí quyết là tôi phải làm kiên trì của Contract
và TotalReturnSwap
thực thể trong cùng một giao dịch.
Đôi khi có thể là một loạt các thực thể phải được lưu giữ lâu dài trong cùng một giao dịch.
Tôi đã nhận thấy ngoại lệ sau khi tôi lưu thực thể TotalReturnSwap
(thường được thực hiện sau khi tôi đã lưu thực thể Contract
).
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:675) \
at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:147)
at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.performTDWPersistenceForContracts(DownstreamContractBusinessEventPostingService.java:102)
at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.persistContractBusinessEvent(DownstreamContractBusinessEventPostingService.java:87)
at com.rbs.fcg.publishing.DownstreamContractBusinessEventPostingService.publish(DownstreamContractBusinessEventPostingService.java:67)
at com.rbs.fcg.publishing.PublishingProcessor.publish(PublishingProcessor.java:76)
at com.rbs.fcg.publishing.PublishingProcessor.process(PublishingProcessor.java:52)
at com.rbs.are.MultiThreadedQueueItemProcessor$2.run(MultiThreadedQueueItemProcessor.java:106)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
Bây giờ một vài điểm có thể giúp trong khi câu hỏi trả lời:
- Tôi chỉ tiết kiệm (chèn) các thực thể trong cơ sở dữ liệu - không bao giờ cập nhật/xóa/đọc
- tôi đã có thể để cô lập ngoại lệ này ngay cả trong môi trường luồng đơn, do đó, nó không giống như một vấn đề đa luồng, mặc dù ứng dụng của chúng tôi là đa luồng
Về # 5, làm thế nào chúng ta có thể giải quyết nó? – Stony
@Stony Có lẽ một 'Làm mới()'? – Michael
@Michael Vấn đề của tôi là 2 chủ đề sửa đổi cùng một PO cùng một lúc; vì vậy khi lưu PO, làm lý do số 5, hãy ném một ngoại lệ. vì vậy khi gọi refresh() trong trường hợp? Nếu trước khi lưu(), thay đổi cho PO sẽ biến mất. Cuối cùng, tôi đã sử dụng khóa LockMode.PESSIMISTIC_WRITE để giải quyết vấn đề của mình. Bất kỳ ai có một giải pháp tốt hơn? – Stony