Hibernate错误会使@PostPersist方法中的实体存在

我在数据库中有一个奇怪的双重插入错误。 我有以下类:

  • TestEntity - 使用@PrePersist和@PostPersist方法的实体。
  • Auditoria - 审计实体
  • 数据集 - DatasetBean的接口
  • DatasetBean - 实现Dataset的无状态bean
  • DatasetFactory - 实例数据集的EJB(查找)
  • 我在junit测试中发现了这个问题(我正在使用嵌入式Glassfish):

    @Test
    public void test() throws NamingException {
        Dataset<TestEntity> dataset = this.lookupBy(DatasetBean.class);
        Assert.assertNotNull(dataset);
    
        TestEntity t = new TestEntity();        
        t.setName(UUID.randomUUID().toString());
    
        dataset.insert(t);
        System.out.println("end");
    }
    

    测试流程如下:

  • 在开始Dataset对象之后,我尝试插入一个TestEntity对象

    @Stateless @EJB(name =“...”,beanInterface = Dataset.class)public class DatasetBean implements Dataset {

    @PersistenceContext(type = PersistenceContextType.TRANSACTION)
    private EntityManager entityManager;
    
    @Override
    public void insert(T entidade) {
        LOG.info("Inserting: " + entidade);
        entityManager.persist(entidade);
    }
    //...
    

    }

  • 使用DatasetFactory,我尝试在TestEntity的@PostPersist方法中插入一个审计实体

    public class DatasetFactory {public static Dataset createDataset(){try {return(Dataset)new InitialContext()。lookup(“...”); } catch(Exception ex){throw new RuntimeException(ex); }}}

    @Entity public class TestEntity实现MyEntity {@Id private Integer id; 私人字符串名称; //设置并获取

    @PrePersist
    public void fillId() {
        if (getId() == null || getId() == 0) {
            Dataset d = DatasetFactory.createDataset();
            Integer i = (Integer) d.fetchJPQLFirstResult("SELECT MAX(te.id) FROM TestEntity te");
            if (i == null || i < 100) {
                setId(100);
            } else {
                setId(i + 1);
            }
        }
    }  
    
    @PostPersist
    public void audit() {
        Dataset<Auditing> dataset = DatasetFactory.createDataset();
        // dataset.getEntityManager().clear();
        Auditing auditing = new Auditing();
        auditing.setIdEntidade(String.valueOf(this.getId()));
        dataset.insert(auditing);
    }
    

    }

    @Entity public class Auditoria实现MyEntity {@Id @GeneratedValue(strategy = GenerationType.IDENTITY)private Integer id; 私人字符串idEntity; //设置并获取}

    公共接口MyEntity扩展Serializable {Integer getId(); }

  • 日志:

    信息:嵌入已成功部署在47.154毫秒。 PlainTextActionReporterSUCCESSDescription:部署名为embedded的AdminCommandApplication。

    2012-01-06 02:56:54,826 [main] INFO com.joaosavio.model.db.DatasetBean(DatasetBean.java:30) - 插入:TestEntity {id = null,name = ea5c2af4-0ca7-48a2-a82a-dbf582c570a9 }

    休眠:从TestEntity中选择max(testentity0_.id)作为col_0_0_ testentity0_

    Hibernate:插入TestEntity(name,id)值(?,?)

    2012-01-06 02:56:56,344 [main] INFO com.joaosavio.model.db.DatasetBean(DatasetBean.java:30) - 插入:Auditoria {id = null,idEntidade = 100}

    Hibernate:插入TestEntity(name,id)值(?,?)

    2012-01-06 02:56:56,350 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper(SqlExceptionHelper.java:143) - SQL错误:2627,SQLState:23000

    2012-01-06 02:56:56,352 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper(SqlExceptionHelper.java:144) - 违反PRIMARY KEY约束'PK_TestEntity_76818E95'。 无法在对象'dbo.TestEntity'中插入重复键。

    06/01/2012 02:56:56 com.sun.ejb.containers.BaseContainer postInvoke

    WARN:在调用EJB DatasetBean方法期间发生系统异常public void com.joaosavio.model.db.DatasetBean.insert(java.lang.Object)javax.ejb.TransactionRolledbackLocalException:从bean抛出的异常...

    原因:javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException:违反PRIMARY KEY约束'PK_TestEntity_76818E95'。 无法在对象'dbo.TestEntity'中插入重复键。 ...

    造成者:org.hibernate.exception.ConstraintViolationException:违反PRIMARY KEY约束'PK_TestEntity_76818E95'。 无法在对象'dbo.TestEntity'中插入重复键。

    注意事项:

    依靠这样一个事实,即如果在插入审计实体之前清除实体管理器(TestEntity中的@PostPersist方法中的代码),我认为TestEntity在事务中陷入困境,这一切都可以正常工作。

    我究竟做错了什么???


    我曾经见过一个非常类似的问题......你应该---

    对@PostPersist要非常小心! hibernate bean持久化或保存操作与数据库插入不一样!

    问题可能在于,假定在插入数据后调用@PostPersist方法....但是,情况并非总是如此! PostPersist方法是回调,但他们不是数据库的回调! 正如你所知 - hibernate可能没有提交你的事务并完全刷新它。 如果您尝试使用PostPersist来协调数据库事务之间的障碍,那么您就犯了一个错误。

    解决方法是在一个正确计划和管理的事务中完成所有的插入操作,然后按键和级联完成,以便hibernate能够以正确的方式为您组织插入操作---或者只是硬编码存储过程来完成为你工作。

    我想你可能会在这里合并有状态和无状态的事务逻辑。

    链接地址: http://www.djcxy.com/p/54071.html

    上一篇: Hibernate error persists an entity in @PostPersist method

    下一篇: OGNL setValue target is null