EntityManager from LocalContainerEntityManagerFactoryBean does not persist entities into the database
Clash 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
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.
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