在从数据库中删除记录后,EclipseLink 2.5在持久化实体时仍然会抛出IntegrityConstraintViolation

时间:2013-06-25 20:40:25

标签: java jpa eclipselink

这是序列:

  1. App1:ID = 1的数据库上的持久实体。没问题。
  2. App2:外部应用程序删除ID = 1的同一记录。没问题。
  3. App1:尝试再次保留以前被App2删除的实体,此处抛出一个异常,说明" IntegrityConstraintViolation",好像该记录仍在数据库中,并且我将其插入两次,不是。
  4. 正如我所看到的,EntityManager正在使用缓存来验证数据库的完整性。不知怎的,甚至在我打电话之后

    getEM().getEntityManagerFactory().getCache().evictAll(); or getEM().clear();

    EntityManager以某种方式将该记录保存在缓存中,并且我已经没有关于如何清除缓存的想法。我找到的一个解决方法是从App1调用:

    getEM().remove(entity.class, id);

    它有效地从数据库和EntityManager缓存中删除记录。但是,这不是重点,它只是证明它使用缓存进行验证,但主要问题仍然存在,"我不能在从另一个应用程序中删除后再次保留记录"。 / p> 顺便说一句,我也试过刷新实体,但也不起作用。它抛出一个例外,说实体不受管理。

    有人对如何解决这个问题有任何想法吗?

2 个答案:

答案 0 :(得分:1)

App2是否提交了交易?

从数据库中抛出IntegrityConstraintViolation,因此它意味着旧行仍然存在于数据库中。

打开最好的日志记录并包含两个应用程序的日志和完整的异常堆栈跟踪。

一般来说,转世物体通常不是一个好主意。最好使用新的id创建一个新对象,或者至少分离/复制到旧对象。

如果另一个应用程序正在访问同一个数据库,您可以考虑禁用缓存,

http://wiki.eclipse.org/EclipseLink/FAQ/How_to_disable_the_shared_cache%3F

否则,如果您只想刷新这个对象的缓存,首先调用find()以确保对象被管理,然后调用refresh()将其从共享缓存中删除。 (然后您需要分离()它,或清除()您的EntityManager或创建一个新的。)

答案 1 :(得分:0)

最终解决了这个问题,这个版本的EclipseLink 2.5与以前的版本有点不同,这是其中一个不同之处。问题是我在TestClass的'tearDown()'方法中执行这一行:

em.CreateQuery("delete from mytable").executeUpdate();

清理数据库中的表。即使此行有效地从数据库中删除记录,如果您使用相同的EntityManager,则无论您执行什么操作,它都不会将其从缓存中删除。因此,我只是移动了查询并在 mytable 实体类中创建了 @NamedQuery 注释,并调用了NamedQuery而不是直接执行SQL。所以,我在'tearDown()'方法中的代码最终成为:

em.CreateNamedQuery("emptyMyTableQuery").executeUpdate();

和@NamedQuery:

@NamedQuery(name="emptyMyTableQuery", query="delete from mytable")

现在它完美无缺。

老实说,即使在早期版本的EclipseLink中出现,我也不得不说这个新版本2.5在几个方面有一些增强和改进,并且修复了很少的错误。嗯,希望这有助于有人发现同样的问题。