为什么在带有@OrderColumn的@ManyToMany支持的List中出现间隙

时间:2014-11-12 02:45:58

标签: java hibernate jpa pessimistic-locking

我们将Ticket对象的队列持久保存到数据库中。我们包含队列的实体如下所示:

@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),另一个操作将新票证添加到队列末尾(调用此newTicket)。

当两个操作交错在同一个队列上时,操作基本上起作用,但我们的队列中最后会出现“缺口”。在数据库中,这看起来像表中的order列中缺少索引,如下所示:0,1,2,4。当队列加载回Java时,缺少的索引将成为队列中的null元素。 / p>

我们在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。

在执行此序列之后,断言从另一个线程触发,该线程检查队列中的空条目。神秘的是,队列基本上是正确的(X被删除,Y被添加到结尾),但是在Y之前的顺序列中有一个间隙。

非常感谢任何关于我们做错事的建议!

1 个答案:

答案 0 :(得分:0)

您是锁定单行,还是所有线程锁定了一个常见的队列&#39;行?如果是后者,请记住,您需要在希望锁定的整个时间内维护一个事务。如果是前者,锁定单个(不同)行不会做任何事情来防止交错操作。

您没有提及您正在使用的后端,但有时数据库记录工具(如SQL Server的分析器和活动监视器)可以帮助您确定正在发生的事情,因为您可以获取发布到数据库的所有SQL语句的有序列表。