我在数据库中两次插入有一个奇怪的错误。我有以下 class :

  • TestEntity-具有@PrePersist和@PostPersist方法的实体。
  • Auditoria-审计实体
  • 数据集-DatasetBean的接口
  • DatasetBean-实现数据集
  • 的无状态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");
    }
    

    测试流程如下:
  • 在获取数据集对象之后,我尝试插入一个TestEntity对象

    @无状态
    @EJB(name =“...”,beanInterface = Dataset.class)
    公共类DatasetBean实现数据集{
    @PersistenceContext(type = PersistenceContextType.TRANSACTION)
    private EntityManager entityManager;
    
    @Override
    public void insert(T entidade) {
        LOG.info("Inserting: " + entidade);
        entityManager.persist(entidade);
    }
    //...
    

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

    公共类DatasetFactory {
    公共静态数据集createDataset(){
    尝试{
    返回(数据集)new InitialContext()。lookup(“...”);
    } catch(异常例外){
    抛出新的RuntimeException(ex);
    }
    }
    }

    @实体
    公共类TestEntity实现MyEntity {
    @ID
    私有整数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);
    }
    

    }

    @实体
    公共类Auditoria实现MyEntity {
    @ID
    @GeneratedValue(策略= GenerationType.IDENTITY)
    私有整数ID;
    私有字符串idEntity;
    //设置并获取
    }

    公共接口MyEntity扩展了Serializable {
    整数getId();

  • 日志:

    INFO:嵌入式已成功部署47.154毫秒。
    PlainTextActionReporterSUCCESSDescription:部署带有嵌入式名称的AdminCommandApplication。

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

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

    休眠:插入值(?,?)到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}

    休眠:插入值(?,?)到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]错误org.hibernate.engine.jdbc.spi.SqlExceptionHelper(SqlExceptionHelper.java:144)-违反主键约束'PK_TestEntity_76818E95'。无法在对象'dbo.TestEntity'中插入重复键。

    2012年6月1日02:56:56 com.sun.ejb.containers.BaseContainer postInvoke

    警告:调用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'中插入重复键。

    注意事项:

    如果我在插入Auditing实体(TestEntity的@PostPersist方法中的已输入代码)之前清除实体管理器,则一切正常,我相信TestEntity会卡在事务中。

    我究竟做错了什么???

    最佳答案

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

    使用@PostPersist时要格外小心!休眠bean的持久或保存操作与数据库插入不同!

    问题可能是您假设在插入数据后调用了@PostPersist方法....但是,并非总是如此! PostPersist方法是回调,但它们不是数据库的回调!如您所知-休眠可能尚未提交您的事务并完全刷新了它。如果您尝试使用PostPersist来协调数据库事务之间的障碍,则说明您犯了一个错误。

    解决方案是在一个正确计划和管理的事务中完成所有插入操作,并计算出密钥和级联,以便hibernate能够以正确的方式为您组织插入操作-或仅对存储过程进行硬编码即可为您工作。

    我认为您可能在这里合并有状态和无状态事务逻辑。

    09-08 07:08