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

Java 从数据库中删除记录后,EclipseLink 2.5在持久化实体时仍然抛出IntegrityConstraintViolation,java,jpa,eclipselink,Java,Jpa,Eclipselink,这是顺序: App1:ID为1的数据库上的持久化实体。没问题 App2:外部应用程序删除ID为1的同一记录。没问题 App1:尝试再次持久化之前被App2删除的实体,这里抛出一个异常,称为“IntegrityConstraintViolation”,就好像记录仍在数据库中一样,我将插入它两次,但事实并非如此 正如我所看到的,EntityManager正在使用缓存来验证数据库的完整性。不知怎的,即使在我打电话之后 getEM().getEntityManagerFactory().getCache

这是顺序:

  • App1:ID为1的数据库上的持久化实体。没问题
  • App2:外部应用程序删除ID为1的同一记录。没问题
  • App1:尝试再次持久化之前被App2删除的实体,这里抛出一个异常,称为“IntegrityConstraintViolation”,就好像记录仍在数据库中一样,我将插入它两次,但事实并非如此
  • 正如我所看到的,EntityManager正在使用缓存来验证数据库的完整性。不知怎的,即使在我打电话之后

    getEM().getEntityManagerFactory().getCache().ReceictAll();或
    getEM().clear()

    EntityManager以某种方式将该记录保存在缓存中,而我对于如何清除该缓存已经没有什么想法了。我发现的一个解决方法是从App1调用:

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

    它还可以有效地从数据库和EntityManager缓存中删除记录。但是,这并不是重点,它只证明它正在使用缓存进行验证,但主要问题仍然存在,“在从另一个应用程序删除记录后,我无法再次持久化该记录”

    顺便说一句,我还尝试刷新实体,但也不起作用。它抛出一个异常,表示该实体未被管理


    有人知道如何解决这个问题吗?

    App2是否提交事务

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

    打开finest并包含两个应用程序的日志和完整的异常堆栈跟踪

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

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


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

    最终解决了这个问题,这个版本的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在几个方面进行了一些增强和改进,修复的bug也很少。好的,希望有人发现了同样的问题,这会有所帮助。

    步骤1和3是使用EntityManager的同一实例执行的,还是为每个操作创建一个新实例?是使用“持久化”还是“合并”?如果它使用乐观锁定,请尝试清除版本fieldHi@davidevesque,是的,它对插入和删除这两个操作使用相同的EntityManager。事实上,为了包含更多信息,出现这种情况的场景是在运行多个方法的测试用例时。我称之为App1的是测试类的
    methodA
    ,App2的是
    tearDown
    方法。几个方法和
    tearDown
    方法之间发生交互,其中所有测试用例在数据库上创建记录以进行测试,
    tearDown
    方法清理数据库,以便下一个测试用例可以在干净的数据库上开始执行。@Chris当然使用persist。