【发布时间】:2012-02-03 22:35:28
【问题描述】:
我在数据库中出现了一个奇怪的双重插入错误。我有以下课程:
- TestEntity - 具有@PrePersist 和@PostPersist 方法的实体。
- 审计 - 审计实体
- Dataset - DatasetBean 的接口
- DatasetBean - 实现 Dataset 的无状态 bean
- DatasetFactory - 实例化 Dataset 的 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 对象
@无状态 @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 方法中插入一个审计实体
公共类数据集工厂 { 公共静态数据集 createDataset() { 尝试 { return (Dataset) new InitialContext().lookup("..."); } 捕捉(异常前){ 抛出新的 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(); }
日志:
信息:嵌入式已在 47.154 毫秒内成功部署。 PlainTextActionReporterSUCCESSDescription:部署 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}
Hibernate: select max(testentity0_.id) as col_0_0_ from TestEntity testentity0_
休眠:插入到 TestEntity(名称,id)值(?,?)
2012-01-06 02:56:56,344 [main] INFO com.joaosavio.model.db.DatasetBean (DatasetBean.java:30) - 插入:Auditoria{id=null, idEntidade=100}
休眠:插入到 TestEntity(名称,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”中插入重复键。
06/01/2012 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:违反主键约束“PK_TestEntity_76818E95”。无法在对象“dbo.TestEntity”中插入重复键。 ...
原因:org.hibernate.exception.ConstraintViolationException:违反主键约束“PK_TestEntity_76818E95”。无法在对象“dbo.TestEntity”中插入重复键。
注意事项:
如果我在插入审计实体(TestEntity 中 @PostPersist 方法中的注释代码)之前清除实体管理器,一切正常,我相信 TestEntity 卡在事务中。
我做错了什么???
【问题讨论】:
标签: java hibernate jpa entity lifecycle