2011-09-20 42 views
0

我目前正在使用JPA(Hibernate)的多租户applcation。对于某些表格,我需要一个对每个租户都唯一的序号。因此,我不能在这些字段中使用@GeneratedValue。我决定使用一个名为Sequence的额外实体,其中long字段的注释为@Version。当请求一个新的ID我做到以下几点:JPA(多租户)中的唯一ID

Sequence seq = em.find(Sequence.class, pk, LockModeType.PESSIMISTIC_FORCE_INCREMENT); 
long nextId = seq.id; 

这个工作,只要我不运行应用程序的两倍。然后我得到以下异常:线程“main” javax.persistence.OptimisticLockException

异常: org.hibernate.StaleObjectStateException:行被更新或者通过 另一个事务删除(或者未保存值的映射是不正确的)

序列没有被锁定“正常”,并且一旦我提交就会得到异常。由于JPA不支持嵌套事务,因此我无法提前检测到它。我尝试了其他一些东西,但他们也失败了。

那么,有没有其他(便携式)解决方案可以让我在多租户环境中生成唯一的密钥?

回答

0

您没有正确使用@Version注释。此批注将数字字段设计为版本字段,并在执行事务锁定时由JPA在内部使用。你不应该写甚至(除了某些情况之外)阅读它。你的初衷是正确的:制作一个音序器,但你不需要使用@Version。每次需要一个新的唯一值时,只需添加一个原子整数的类,然后将其保存到表中的数据库中。

+0

我已经试过你的建议。这个解决方案的问题在于,我没有检测到事务重叠,直到我提交了整个事务(这就是我的意思是嵌套事务)。 – Dominik

+0

那么,你不会喜欢我的建议,但是如果你真的想要嵌套事务,你可能想要抛弃Hibernate/JPA。您可以直接访问JDBC,或者使用Spring SavePoints(使用JDBC)来模拟嵌套事务:http://static.springsource.org/spring/docs/2.5.5/api/org/springframework/transaction/SavepointManager.html –