Spring #PersistenceContext how to inject manually the entity manager in my GenericDao - spring

Hallo all:
I read the spring reference about this point.
I would choose to use the #PersistenceContext in my DAO to inject a shared transactional entity manager, but since I use the GenericDaoJpaImpl pattern over two entityManagerFactories that point to 2 different persistence units I cannot use it.
So right now in my application I have this configuration:
entityManagerFactoryies:
<bean id="entityManagerFactoryIban0" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/contratto-persistence-iban0.xml" />
</bean>
<bean id="entityManagerFactoryCont0" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:META-INF/contratto-persistence-cont0.xml" />
</bean>
<bean abstract="true" id="abstractDaoJpaImplIban0" lazy-init="false">
<property name="entityManagerFactory" ref="entityManagerFactoryIban0" />
</bean>
<bean abstract="true" id="abstractDaoJpaImplCont0" lazy-init="false">
<property name="entityManagerFactory" ref="entityManagerFactoryCont0" />
</bean>
Then each of my DAOs is an instance of the GenericDaoImpl:
#Repository
public class GenericDaoJpaImpl<T, ID extends Serializable> implements GenericDao<T, ID> {
private Class<T> entityClass;
private EntityManagerFactory entityManagerFactory;
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
public GenericDaoJpaImpl() {
super();
}
public GenericDaoJpaImpl(Class<T> entityClass) {
super();
this.entityClass = entityClass;
}
/**
* #see it.alten.intesasanpaolo.contratto.dao.common.GenericDao#getItemByID(java.io.Serializable)
*/
#Override
public T getItemByID(ID id) {
EntityManager em = entityManagerFactory.createEntityManager();
return em.find(entityClass, id);
}
I construct my dao via spring in this way:
<bean id="eventMessageDao" parent="abstractDaoJpaImplCont0" class="it.alten.intesasanpaolo.contratto.dao.common.GenericDaoJpaImpl">
<constructor-arg>
<value>it.alten.intesasanpaolo.contratto.domain.event.OnlineEventMessage</value>
</constructor-arg>
</bean>
Now I would like to modify the GenericDaoJpaImpl as described in the spring documentation not to be associated to the entityManagerFactory from which I have to create every time the entityManager but directly to the entityManager.
I would like to define it in the context in a way I can inject it to the correct abstract dao to be extended from every dao.
<bean abstract="true" id="abstractDaoJpaImplIban0" lazy-init="false">
<property name="entityManagerFactory" ref="entityManagerFactoryIban0" />
</bean>
How can I achieve this?
kind regards
Massimo

You can use SharedEntityManagerBean to construct a transactional EntityManager from the EntityManagerFactory:
<bean id="entityManagerFactoryIban0"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
<bean id="entityManagerIban0"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactoryIban0" />
</bean>
<bean abstract="true" id="abstractDaoJpaImplIban0" lazy-init="false">
<property name="entityManager" ref="entityManagerIban0" />
</bean>

You can provide the persistence unit name in the xml configuration, using the SharedEntityManagerBean, like below:
<bean id="testDao" class="com.test.persistence.dao.BaseDAO">
<property name="entityManager">
<bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="persistenceUnitName" value="persistence-test-unit" />
</bean>
</property>
</bean>
of course, you can have the SharedEntityManagerBean as a separate bean
Here, I m injecting entityManager into BaseDAO as you're doing using #PersistenceContext(unitName="...")

Related

Data is not getting inserted in JPA Spring weblogic

I have following configuration in application context
<jee:jndi-lookup id="dataSource" jndi-name="MY_DS" />
<context:load-time-weaver/>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceUnitName" value="pu_TEST" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
Now my DAO Class
#Repository
public class EmployeeDAO{
#PersistenceContext
private EntityManager em;
#Transactional
public void create(Employee entity) {
LOG.error("Enitity Manager:create" + em);
em.persist(entity);
// em.flush(); if i use flush it saves
}
}
Now when I save the entity it does not say give any error but no data is updated into db.
I do not wish to use flush as entitymanager is injected by spring and should perform flush at the end automatically which is not happening. correct my understanding.
Adding facade class may be issue is there, Does Propagation.REQUIRES_NEW has anything to do here?
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void process(){
Employee e = factory.getEmployee();
employeeDao.create(e);
}
On Debug after create method call it shows employee got primary key populated that mean db call has made but at the end it is not persisted.
Please try either of the 3 :
1.Solution 1
Please call below code
em.joinTransaction();
just before
em.persistEntity(entity);
2.Solution 2
make attribute readOnly=false in #Transactional
3.Solution 3
Try manually adding bean EmployeeDAO in spring xml file
or else you can try below:
#Transactional(propagation=Propagation.REQUIRED)

Could not open JPA EntityManager for transaction using MongoDB

Trying to use Spring, Hibernate-OGM with MongoDB. However getting an issue with transactions. I know they are not supported by MongoDB however I want to use annotation #transactional so I dont have to do begin, commit.
Exception
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:430)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:420)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:257)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
DB context.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="mongo-hibernate"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
persistence.xml
<persistence-unit name="mongo-hibernate" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<properties>
<property name="hibernate.current_session_context_class" value="thread"/>
<property name="hibernate.ogm.datastore.provider" value="mongodb"/>
<property name="hibernate.ogm.datastore.grid_dialect" value="org.hibernate.ogm.datastore.mongodb.MongoDBDialect"/>
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="hibernate.ogm.datastore.database" value="mongodbtest"/>
<property name="hibernate.ogm.mongodb.database" value="mongodbtest"/>
<property name="hibernate.ogm.mongodb.host" value="localhost"/>
<property name="hibernate.ogm.mongodb.associations.store" value="IN_ENTITY"/>
</properties>
</persistence-unit>
</persistence>
DAO
#PersistenceContext
protected EntityManager entityManager;
#Transactional(readOnly = false)
public <E> void updateObject(E entity) {
entityManager.persist(entity);
}
any help is appreciated. Thank you
So far I moved a little further, I changed some files to:
DB context.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="mongo-hibernate"/>
</bean>
<bean class="com.arjuna.ats.jta.TransactionManager" factory-method="transactionManager" id="arjunaTransactionManager"/>
<bean class="com.arjuna.ats.jta.UserTransaction" factory-method="userTransaction" id="arjunaUserTransaction"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="arjunaTransactionManager"/>
<property name="userTransaction" ref="arjunaUserTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
DAO:
#PersistenceContext
protected EntityManager entityManager;
#Transactional(readOnly = false)
public <E> void updateObject(E entity) {
Session session = entityManager.unwrap(Session.class);
org.hibernate.Transaction tx = session.getTransaction();
tx.begin();
session.persist(entity);
tx.commit();
}
This way eveything is working fine, however I would really like it to work more simplier like:
#Transactional(readOnly = false)
public <E> void updateObject(E entity) {
entityManager.persist(entity);
}
Any suggestions?
Yup, I have a suggestion: Read the docs. ;)
"MongoDB does not support transaction."

Spring + #Transactional: can't rollback in case of error

I am trying to implement the following: I need to add two different entities in same same transaction to database.
I have different DAO classes and Service classes for each entity.
public class InvoicesDAO {
#Autowired
protected SessionFactory sessionFactory;
public void save(Invoice object) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
session.persist(object);
}
}
public class RequestsDAO {
#Autowired
protected SessionFactory sessionFactory;
public void save(Request object) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
session.persist(object);
}
}
public class InvoicesService {
#Autowired
private InvoicesDAO invoicesDAO;
#Autowired
private RequestsDAO requestsDAO;
#Transactional
public void add(Invoice object) throws HibernateException {
invoicesDAO.save(object);
}
#Transactional
public void updateAndGenerate(Invoice object1, Request object2) throws HibernateException {
invoicesDAO.save(object1);
requestsDAO.save(object2);
}
}
The config:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:/hibernate.properties" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ejl.butler.object.data" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<context:annotation-config />
<context:component-scan base-package="com.service" />
<bean id="invoicesDao" class="com.dao.InvoicesDAO" />
<bean id="requestsDao" class="com.dao.RequestsDAO" />
Controller:
//***
/**
* Invoices access service
*/
#Autowired
private InvoicesService invoicesService;
// objects creation
invoicesService.updateAndGenerate(invoice, request);
//***
So when I am trying to call updateAndGenerate method and pass there invalid values for object2 - it fails without rolling back the object1. How can I fix it? Thank you
I dont think it is got to do with Proxies. You dont need a proxy object here. Generally you need a proxy object for instances such for a login service etc where you need a proxy object for the singleton bean definition. But, the only way it can not rollback is if your propogation level on the Transaction isnt correct.
If you use a Trasaction.REQUIRES_NEW then the dao.save wouldnt rollback and it wouldnt tie back to the outer transaction and hence wouldnt rollback.
Finally I figured out where the problem was so I will answer my own question...
According to Declarative transactions (#Transactional) doesn't work with #Repository in Spring and https://stackoverflow.com/a/3250959/705869 the order of the base-package items inside context:component-scan directive is very important. In additional, you should put only really necessary packages.
I had some duplicates inside this directive so the application context was initialized before database context. And that's why transactions were disabled inside services!
So check twice for base-package packages inside context:component-scan and remove unnecessary ones.

Why Spring doesn't intercept transaction?

Tried to configure Spring for tests with hibernate and transactions. Getting bean from app context which is marked with #Transactional transaction isn't intercepted. What I could miss in configuration?
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<import resource="spring-dao.xml"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="userService" class="com.test.service.UserServiceimpl">
<property name="userDao" ref="userDao"/>
</bean>
public interface UserService {
public abstract User loadUserById(long userId);
#Transactional
public abstract void doSomething();
}
public class UserServiceimpl implements UserService {
#Override
public void doSomething() {
User user = loadUserById(1);
user.fillUpMoney(999);
userDao.update(user);
throw new RuntimeException("Shpould be rollback");
}
Don't annotate the abstract method as transactional, annotate the concrete implementation.
Do not user BeanFactory ;)
http://forum.springsource.org/showthread.php?122292-Sprinng-doesnt-intercept-transaction

JPA Detected reentrant flush

I have little problem with openjpa implementation of jpa with spring 2.5. My dao method:
#Transactional
public User getUserByName(final String name) {
return (User) getEntityManager().createQuery("select u from User as u where u.name = :name").setParameter("name", name).getSingleResult();
}
returns org.springframework.dao.InvalidDataAccessApiUsageException:
org.apache.openjpa.persistence.InvalidStateException: Detected reentrant flush. Make sure your flush-time instance callback methods or event listeners do not invoke any operations that require the in-progress flush to complete.
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:1904)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1679)
at org.apache.openjpa.kernel.QueryImpl.isInMemory(QueryImpl.java:956)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:838)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:779)
at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:525)
at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:254)
at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:317)
at org.jpa.dao.UserDao.getUserByName(UserDao.java:71)
//EDIT
EntityManager settings:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="showSql" value="false"/>
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaDialect"/>
</property>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
How do you obtain an EntityManage? In dao class:
#PersistenceContext(type = PersistenceContextType.EXTENDED)
protected EntityManager entityManager;
What is wrong? Any idea?
I have the same problem, and modify my entity for the primary key:
#Id
//#Basic(optional = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
maybe can help you.

Resources