Ticket 개체의 큐가 데이터베이스에 보관됩니다. 큐를 포함하는 우리의 실체는 다음과 같습니다@OrderColumn을 사용하여 @ManyToMany가 지원하는 List에 간격이 나타나는 이유
@Entity
public class StoreQueueCollection {
@Id
private int storeId;
@ManyToMany(fetch=FetchType.LAZY)
@OrderColumn
private List<Ticket> mainQueue = new ArrayList<Ticket>();
@ManyToMany(fetch=FetchType.LAZY)
@OrderColumn
private List<Ticket> cancelledQueue = new ArrayList<Ticket>();
.. etc
우리가 큐의 끝 (호출에 새 티켓을 추가 한 (이 changeStatus 전화) 다른 하나의 큐에서 티켓을 이동 작동하고, 다른 이 새로운 Ticket).
두 작업이 같은 큐에서 인터리브 될 때 작업은 기본적으로 작동하지만 큐에 "갭"이 생깁니다. 데이터베이스에서 이것은 다음과 같이 테이블의 순서 열에 누락 된 색인 (0, 1, 2, 4)처럼 보입니다. 대기열이 Java로 다시로드되면 누락 된 색인은 대기열의 널 (null) 요소가됩니다.
일관성없는 인터리브 업데이트를 방지하기 위해 StoreQueueCollection 객체에서 비관적 잠금을 사용하지만 예상대로 작동하지 않습니다. 추가 로깅, 우리는 다음과 같이 이상한 시퀀스를 참조하십시오
- changeTicketStatus() starts - lock the queue using entityManager.refresh() - ticket X removed from front of queue A - queue is entityManager.flush()ed * newTicket() starts * creates a new ticket Y, locks the StoreQueueCollection using entityManager.refresh(); * ticket Y added to the end of queue A * ticket Y has fields initialized and is save()d * call refresh(), method is blocked - changeTicketStatus() resumes (printing in-memory queue shows that ticket X is not in queue A) - ticket X added to another queue B - ticket X has some fields modified - ticket X is saved using repository.save() (printing in-memory queue shows that ticket X is not in queue A) - changeTicketStatus() completes * newTicket() resumes * refresh() returns (printing in-memory queue A shows that ticket X is still in queue!) * ticket Y is added to end of queue A (printing in-memory queue A shows that ticket X and Y are in the queue) * queues are save()d
모든 잠금은 LockModeType.PESSIMISTIC_WRITE을하고 범위 PessimisticLockScope.EXTENDED입니다.
이 실행 순서 후에, 어설 션은 다른 스레드에서 큐에있는 null 항목을 검사합니다. 신비하게도 대기열은 기본적으로 정확합니다 (X가 삭제되고 끝에 Y가 추가됩니다). 그러나 Y 이전에 주문 열에 틈이 있습니다.
잘못된 점에 대한 제안은 대단히 감사합니다!
로크에 문제가있는 것 같습니다. 잠금 및 트랜잭션 경계 코드의 간단한 샘플을 제공 할 수 있습니까? – gerrytan
답장을 보내 주셔서 감사합니다. 불행히도 그것은 약간 크고 방법에 걸쳐 펼쳐져 있습니다. – bsa
SQL 수준에서 로깅 (log4jdbc-log4j2 사용), 확실히 잠금이 예상대로 작동하지 않는 것처럼 보입니다. 문서를 다시 읽어야하는 것 같습니다. – bsa