EntityManager from LocalContainerEntityManagerFactoryBean does not persist entities into the database

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



EntityManager from LocalContainerEntityManagerFactoryBean does not persist entities into the database



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).


EntityManager


@PersistenceContext


@Transactional


AddDao


entityManager.persist()



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.


.transacted()


@Autowired


EntityManager


@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:


pom.xml


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





You didn't put the code of the entity you're trying to persist in your post, could it be a "large object" case? Check this link. Hope it helps. Edit: I found this.
– n3k0
May 9 '13 at 21:16





Actually it doesn't persist none of the domain objects, neither the large nor the small ones. It persists them to the cache/entityManager but not to the database (which is PostgreSQL btw); after calling em.persist(entity) and immediately after em.contains(entity) the result is true but the entity isn't actually persisted to the database. I'm guessing is has something to do with transactions. Regarding the links, the objects are mapped normally and the transactions are JTA in persistence.xml and not RESOURCE_LOCAL as discussed there.
– m3th0dman
May 9 '13 at 21:25



em.persist(entity)


em.contains(entity)


entity


JTA


persistence.xml


RESOURCE_LOCAL




4 Answers
4



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.





I have tried that, and this doesn't make any difference; what I haven't tried is em.merge(entity), I'll try that.
– m3th0dman
May 10 '13 at 6:58


em.merge(entity)





It also doesn't work with em.merge(entity) with or without em.flush() afterwards.
– m3th0dman
May 10 '13 at 14:42


em.merge(entity)


em.flush()



From the limited symptoms given, seems like the JTA transaction is not being started and propagated. Your EM would work fine up to a point - reading from DB, allowing data changes against it's Persistent Context cache, but never writing to the DB.



Think it's a config problem and your @Transaction annotations are being ignored.



I have enabled annotation-driven transactions.



Make sure it's configured as follows in your Spring configuration:


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



where:


xmlns:tx="http://www.springframework.org/schema/tx"





That's exactly how it the problem. The transaction should have been created by Camel. Besides the namespace there is http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd in xsi:schemaLocation.
– m3th0dman
May 10 '13 at 7:01



http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd


xsi:schemaLocation



So, according with the apache camel jpa documentation, you have to put an URI that describes the behavior of your methods, it describes an option "flushOnSend" maybe you have to add that URI.
Here it describes an example with Hibernate.
And here a class that is a test, maybe you can use it and check if you failed to pass any ;-)





We do not use the Camel JPA component but the Bean component. In Camel Java DSL there isn't from(wherever).process()[...].to("jpa:[entityClassName][?options]") but rather from(wherever).transacted().[...].to("bean:addBean?method=addEntity"). The addBean has as @Autowired an addDao bean which has injected the EntityManager with @PersistenceContext.
– m3th0dman
May 10 '13 at 14:40



from(wherever).process()[...].to("jpa:[entityClassName][?options]")


from(wherever).transacted().[...].to("bean:addBean?method=addEntity")


addBean


@Autowired


addDao


EntityManager


@PersistenceContext



Try the @Transactional in this way


@Component
public class AddDao
@PersistenceContext
private EntityManager entityManager;

@Transactional("BitronixTransactionManager")
public void persistMyEntity(MyEntity myEntity)
entityManager.persist(myEntity);







By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard