I have a weird error of double insert in the DB. I have the following classes:
- TestEntity - entity with a @PrePersist and a @PostPersist methods.
- Auditoria - audit entity
- Dataset - interface of DatasetBean
- DatasetBean - Stateless bean which implements Dataset
- DatasetFactory - instance an EJB of Dataset (lookup)
I put the problem in a junit test (I'm using embedded 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");
}
The flow of the test is the following:
After gettin a Dataset object, I try to insert a TestEntity object
@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); } //...
}
Using the DatasetFactory, I try to insert an Auditing entity in a @PostPersist method of the TestEntity
public class DatasetFactory { public static Dataset createDataset() { try { return (Dataset) new InitialContext().lookup("..."); } catch (Exception ex) { throw new RuntimeException(ex); } } }
@Entity public class TestEntity implements MyEntity { @Id private Integer id; private String name; // sets and gets
@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 implements MyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String idEntity; //sets and gets }
public interface MyEntity extends Serializable { Integer getId(); }
Log:
INFO: embedded was successfully deployed in 47.154 milliseconds. PlainTextActionReporterSUCCESSDescription: deploy AdminCommandApplication deployed with name embedded.
2012-01-06 02:56:54,826 [main] INFO com.joaosavio.model.db.DatasetBean (DatasetBean.java:30) - Inserting: TestEntity{id=null, name=ea5c2af4-0ca7-48a2-a82a-dbf582c570a9}
Hibernate: select max(testentity0_.id) as col_0_0_ from TestEntity testentity0_
Hibernate: insert into TestEntity (name, id) values (?, ?)
2012-01-06 02:56:56,344 [main] INFO com.joaosavio.model.db.DatasetBean (DatasetBean.java:30) - Inserting: Auditoria{id=null, idEntidade=100}
Hibernate: insert into TestEntity (name, id) values (?, ?)
2012-01-06 02:56:56,350 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper (SqlExceptionHelper.java:143) - SQL Error: 2627, SQLState: 23000
2012-01-06 02:56:56,352 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper (SqlExceptionHelper.java:144) - Violation of PRIMARY KEY constraint 'PK_TestEntity_76818E95'. Cannot insert duplicate key in object 'dbo.TestEntity'.
06/01/2012 02:56:56 com.sun.ejb.containers.BaseContainer postInvoke
WARN: A system exception occurred during an invocation on EJB DatasetBean method public void com.joaosavio.model.db.DatasetBean.insert(java.lang.Object) javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean ...
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Violation of PRIMARY KEY constraint 'PK_TestEntity_76818E95'. Cannot insert duplicate key in object 'dbo.TestEntity'. ...
Caused by: org.hibernate.exception.ConstraintViolationException: Violation of PRIMARY KEY constraint 'PK_TestEntity_76818E95'. Cannot insert duplicate key in object 'dbo.TestEntity'.
Considerations:
Relying on the fact that everything works fine if I clear the entity manager before the insertion of the Auditing entity (comented code in @PostPersist method in TestEntity), I believe that the TestEntity is getting stuck in the transaction.
What am I doing wrong???