Java – EntityManager from LocalContainerEntityManagerFactoryBean does not persist entities into the database

apache-cameljavajpaspringtransactions

The problem is that the EntityManager injected with @PersistenceContext in a Spring managed bean does not persist the entities to the database. I have tried using @Transactional on the AddDao bean, where entityManager.persist() is called (I have enabled annotation-driven transactions).

The transaction begins in another bean which is instantiated by Camel with .transacted() in the Camel Java DSL. That bean has an @Autowired property which is the DAO and has the EntityManager injected with @PersistenceContext.

As transaction manager Bitronix is used.

A portion of the Spring xml configuration file looks like this:

  <bean id="localContainerEntityManagerFactoryBean" depends-on="btmConfig" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jtaDataSource" ref="dataSource"/>
    <property name="persistenceUnitName" value="nameFromPersistenceXml"/>
    <property name="persistenceProvider">
        <bean class="org.hibernate.ejb.HibernatePersistence"/>
    </property>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
    </property>
    <property name="packagesToScan" value="package with @Entity POJOs"/>

  </bean>



  <bean id="btmConfig" factory-method="getConfiguration"
      class="bitronix.tm.TransactionManagerServices">
    <property name="serverId" value="spring-btm" />
  </bean>

  <!-- create BTM transaction manager -->
  <bean id="BitronixTransactionManager" factory-method="getTransactionManager"
      class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig"
      destroy-method="shutdown" />
  <!-- Spring JtaTransactionManager -->
  <bean id="springTransactionManager"
      class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="BitronixTransactionManager" />
    <property name="userTransaction" ref="BitronixTransactionManager" />
  </bean>

  <tx:annotation-driven transaction-manager="springTransactionManager" />

Edit: In a overly simplified version it looks like this:

In Camel Java DSL there is

from("wsLayer")
   .transacted()
   .otherProcessing()
   .to("bean:addBean?method=addMyEntity")

And add beans look something like this:

@Component
public class AddBean {
    @Autowired
    private AddDao addDao;

    public void addMyEntity(MyEntity myEntity) {
        //other business logic
        addDao.persistMyEntity(myEntity);
    }
}

@Component
public class AddDao {
    @PersistenceContext
    private EntityManager entityManager;

    //I have tried here 
    //@Transactional and 
    //@Transactional(propagation = PropagationType.REQUIRES_NEW)
    public void persistMyEntity(MyEntity myEntity) {
        entityManager.persist(myEntity);
    }
}

The reading from the database works well.

See the data source:

<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
    init-method="init" destroy-method="close">
    <property name="uniqueName" value="theName" />
    <property name="maxPoolSize" ><value>${db.pool.maxSize}</value></property>
    <property name="minPoolSize" ><value>${db.pool.minSize}</value></property>    
    <property name="allowLocalTransactions" ><value>true</value></property>
    <property name="automaticEnlistingEnabled" ><value>true</value></property>
    <property name="className" ><value>${db.pool.datasource}</value></property>
    <property name="driverProperties" ref="databaseProperties" />
</bean>

where the properties are set in Maven's pom.xml like this:

 db.pool.maxSize=15
 db.pool.maxSize=5
 db.pool.datasource=org.postgresql.xa.PGXADataSource

Best Solution

Did you tried to execute em.flush() after em.persist(entity)? According with the docs of Java EE:

em.persist(entity): Make an instance managed and persistent. BUT em.flush(entity): Synchronize the persistence context to the underlying database.

So, you can do something like:

em.persist(myEntity);
em.flush();

And check if this change make a difference.

Related Question