2011-03-05 378 views
2

我对Hibernate非常不满!捕捉ConstraintViolationException并处理不规则的约束

我有一个数据库表(mysql)拥有父子关系,允许我建立一个类别树。我有多个线程可以尝试获取,如果没有,大致同时创建类别路径(包含几个父子行)。

问题是我只使用TRANSACTION_READ_COMMITTED,所以竞争条件可能发生在线程可以为类别子路径创建父 - 子因为它没有找到它,然后(lo!)的另一个线程同时做到了这一点。为了试图解决这个问题,我在父/子ID上设置了一个唯一的约束,并在完整的类别路径上设置了一个唯一的约束。然后,我希望在我的会话中,我会捕获Hibernate ConstraintViolationException,并且知道另一个线程为我写了新的关系,我查询另一个线程在catch子句中写入的行。并尝试在该线程中继续完成它在会话中需要做的所有事情。

这是我能想到的解决多线程同时获取/创建相同长分类路径(具有多个子父 - 子关系行)的问题的唯一方式,并确保维护了独特的约束。

但是,hibernate会使ConstraintViolationException上的会话无效并最终抛出一个断言异常(“com.stagirite.bean.Category条目中的null id(发生异常后不刷新会话)”),所以我的解决方案是不可行的。

如何在不使用悲观锁的情况下通过我的应用程序解决这个问题:“get/create”模型不创建重复行?

安迪

回答

0

因为我不知道你是如何建模的数据(自引用表或marterialized路径)和相应的Hibernate映射,我要试图回答两个线程正在试图改变部分一样的东西。你有没有尝试过使用休眠版本功能。简而言之,如果一个线程已经更新了一个类别,版本号会增加。另一个可能已经开始更新但未完成更新的线程将看到版本更改和回滚。如果您可以发布您的数据模型,这将有所帮助。

希望有所帮助。

+0

我没有想到版本控制。感兴趣的行是幂等的,这意味着无论线程添加它,将以相同的方式添加它,即具有相同的类别名称和相同的参考ID到其他类别。因此,谁先添加它并没有关系,只是没有重复,并且调用GetAdd函数的线程获取新/旧行的ID。所以我的问题是版本如何解决竞争条件。线程1通过类别名称获得,并发现它不在那里。在同一个事务中它添加了一个休眠版本。看起来似乎可能会出现与版本竞争的情况 – 2011-04-11 15:43:48