-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: Hibernate double insertion using entity lifecycle listener
PostPosted: Thu Jan 05, 2012 1:21 am 
Newbie

Joined: Thu Jan 05, 2012 1:16 am
Posts: 1
Hi people!
I have a weird error of double insert in the DB. I'll summarize the problem and then put the codes.

I have the following classes:
- TestEntity - entity with a @PrePersist method. This entity is staying in the transaction after it is committed by the container
- Auditing - audit entity
- Dataset<T> - interface of DatasetBean<T>
- DatasetBean<T> - Stateless bean which implements Dataset
- DatasetFactory - instance an EJB of Dataset (lookup)
- PersistenceLifeCycleListener - an entity lifecycle listener, defined in orm.xml file (following the example in http://docs.jboss.org/hibernate/core/4. ... eners.html)

I put the problem in a junit test (I'm using embedded Glassfish):
Code:
    @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 test is the following:

1. After gettin a Dataset object, I try to insert a TestEntity object

Code:
   @Stateless
    @EJB(name="java:global/br/com/joaosavio/dataset/Dataset",beanInterface=Dataset.class)
    public class DatasetBean<T> implements Dataset<T> {

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


2. After insertion, the PostPersist listener is called, and I try to insert an auditing entity. Here, if I uncomment //dataset.getEntityManager().clear(), the test passes. Otherwise I got an error (log below).

Code:
    public class PersistenceLifeCycleListener {

        public void postPersist(MyEntity entity) {
            LOG.info("Post-persist event");
            if (!entity.getClass().isAnnotationPresent(ClassNotAuditable.class)) {
                Dataset<Auditing> dataset = DatasetFactory.createDataset(); // basically a lookup
                //dataset.getEntityManager().clear();
                Auditing auditing = new Auditing();
                auditing.setIdEntity(String.valueOf(entity.getId()));
                dataset.insert(auditing);
            }
        }
        ...
    }

Code:
    public class DatasetFactory {
        public static Dataset createDataset() {
            try {
                return (Dataset) new InitialContext().lookup("java:global/br/com/joaosavio/dataset/Dataset");
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }


Log - look out lines 7 and 11, hibernate inserted the same entity twice:
Code:
...
INFO: embedded was successfully deployed in 16.336 milliseconds.
2012-01-05 02:53:27,068 [main] INFO  com.joaosavio.model.db.DatasetBean (DatasetBean.java:30) - Inserting: TestEntity{id=null, name=035a2be3-211f-4d08-b7ad-146c006ea4ea}
2012-01-05 02:53:27,560 [main] INFO  com.joaosavio.event.PersistenceLifeCycleListener (PersistenceLifeCycleListener.java:25) - Pre-persist event
Hibernate: select max(testentity0_.id) as col_0_0_ from TestEntity testentity0_
Hibernate: insert into TestEntity (name, id) values (?, ?)
2012-01-05 02:53:29,099 [main] INFO  com.joaosavio.event.PersistenceLifeCycleListener (PersistenceLifeCycleListener.java:29) - Post-persist event
2012-01-05 02:53:29,102 [main] INFO  com.joaosavio.model.db.DatasetBean (DatasetBean.java:30) - Inserting: Auditoria{id=null, idEntidade=100}
2012-01-05 02:53:29,103 [main] INFO  com.joaosavio.event.PersistenceLifeCycleListener (PersistenceLifeCycleListener.java:25) - Pre-persist event
Hibernate: insert into TestEntity (name, id) values (?, ?)
05/01/2012 02:53:29 com.sun.ejb.containers.BaseContainer postInvoke
AVISO: 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
   at com.sun.ejb.containers.BaseContainer.checkExceptionClientTx(BaseContainer.java:5049)
   at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4884)
   at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2039)
   at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1990)
2012-01-05 02:53:29,108 [main] WARN  org.hibernate.engine.jdbc.spi.SqlExceptionHelper (SqlExceptionHelper.java:143) - SQL Error: 2627, SQLState: 23000
   at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
2012-01-05 02:53:29,109 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper (SqlExceptionHelper.java:144) - Violation of PRIMARY KEY constraint 'PK__TestEntity__65570293'. Cannot insert duplicate key in object 'dbo.TestEntity'.
   at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
   at $Proxy111.insert(Unknown Source)
   at com.joaosavio.event.PersistenceLifeCycleListener.postPersist(PersistenceLifeCycleListener.java:35)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.hibernate.ejb.event.ListenerCallback.invoke(ListenerCallback.java:48)
   at org.hibernate.ejb.event.EntityCallbackHandler.callback(EntityCallbackHandler.java:110)
   at org.hibernate.ejb.event.EntityCallbackHandler.postCreate(EntityCallbackHandler.java:83)
   at org.hibernate.ejb.event.EJB3PostInsertEventListener.onPostInsert(EJB3PostInsertEventListener.java:49)
   at org.hibernate.action.internal.EntityInsertAction.postInsert(EntityInsertAction.java:145)
   at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:123)
   at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:273)
   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:265)
   at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:186)
   at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:323)
   at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
   at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1081)
   at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:315)
   at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.beforeCompletion(SynchronizationCallbackCoordinatorImpl.java:104)
   at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:53)
   at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435)
   at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:852)
   at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5114)
   at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4879)
   at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2039)
   at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1990)
   at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222)
   at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
   at $Proxy111.insert(Unknown Source)
   at com.joaosavio.ContainerTest.test(ContainerTest.java:81)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
   at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
   at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
   at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
   at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
   at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
   at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
   at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
   at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
   at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
   at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
   at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
   at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35)
   at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115)
   at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   at java.lang.reflect.Method.invoke(Method.java:597)
   at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103)
   at $Proxy0.invoke(Unknown Source)
   at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150)
   at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91)
   at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Violation of PRIMARY KEY constraint 'PK__TestEntity__65570293'. Cannot insert duplicate key in object 'dbo.TestEntity'.
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1356)
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1284)
...


persistence.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="simulajava" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/trimpaper</jta-data-source>
    <class>com.joaosavio.model.vo.TestEntity</class>
    <class>com.joaosavio.model.vo.Auditing</class>
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
      <property name="hibernate.current_session_context_class" value="jta"/>
      <property name="hibernate.session_factory_name" value="java:global/hibernate/SessionFactory"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>
</persistence>


orm.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
                 http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
                 version="2.0">
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <entity-listeners>
                <entity-listener class="com.joaosavio.event.PersistenceLifeCycleListener">
                    <pre-persist method-name="prePersist"/>
                    <post-persist method-name="postPersist"/>
                </entity-listener>
            </entity-listeners>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
</entity-mappings>


TestEntity
Code:
@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.criarDataset();
            Integer i = (Integer) d.fetchJPQLFirstResult("SELECT MAX(te.id) FROM TestEntity te", null);

            if (i == null || i < 100) {
                setId(100);
            } else {
                setId(i + 1);
            }
        }
    }
}


Auditing
Code:
@ClassNotAuditable
@Entity
public class Auditing implements MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String idEntity;
    //sets and gets


MyEntity
Code:
public interface MyEntity extends Serializable {
    Integer getId();
}


What am I doing wrong?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.