I'm trying to open multiple transactions​ on a method using #Transactional by Spring framework
And for some reason it's throws java.lang.IllegalStateException : Transaction already active
My method
#Transactional
Public void foo(Entity e){
entityManager.merge(e);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
}
Any idea how to open multiple transaction without getting that error?
I think you may be confusing what the Spring #Transactional annotation means. When you use that annotation you're asking Spring to enrich your method invocation with transaction semantics.
You may want to take a look at the TransactionAspectSupport class, more specifically the method invokeWithinTransaction which is the place where all the magic happens for your transactional methods.
You will see there that before your code is invoked, a new transaction is created, then your code is executed, and after that, either a commit or rollback happens. In other words, Spring's aspect controls the transaction for you.
All these magic needs some configuration for it to happen: you need to make sure that Spring finds your #Transactional methods and enrich them. To do so you need to add a piece of configuration:
<tx:annotation-driven/>
And of course you need to define a transaction manager that can be used by your transactional methods. It seems you're using JPA so a JpaTransactionManager makes sense in this case:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="POSTGRESQL"/>
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
<property name="prepareConnection" value="true"/>
</bean>
</property>
<property name="persistenceUnitName" value="test-api"/>
<property name="packagesToScan">
<list>
<value>com.company.humanresources</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg name="emf" ref="entityManagerFactory"/>
</bean>
Finally, if you want to gain access to the entity manager being used by your current transaction, you can do something like:
#PersistenceUnit(unitName = "test-api")
EntityManagerFactory emf;
#Transactional
public Department addDepartment(String name) {
EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);
Department department = new Department();
department.setName(name);
em.persist(department);
return department;
});
Once more, Spring will control the transaction semantics around your transactional method. You must also take into account that the default Spring behavior only works with public methods.
Related
Im having some trouble understanding the way spring handles the hibernate entities, and does the lazy loading process.
So for this case we have to entities
#Entity
public class EntityA{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany(cascade={CascadeType.PERSIST, CascadeType.REFRESH})
private Collection<EntityB> bss= new ArrayList<EntityB>();
and the agregated entity
#Entity
public class EntityB{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany(mappedBy="bss")
private Collection<EntityA> ass= new ArrayList<EntityA>();
then I have a simple business class marked as transactional:
#Component
#Scope("session")
#Transactional(propagation=Propagation.TRIED_EVERY_SINGLE_ONE)
public class GenericTestBean {
private EntityA entityA;
#Autowired
private IGenericDAO genericDAO;
public GenericTestBean() {
System.out.println("bean creado!");
}
public void testQuery() {
entityA= genericDAO.get(EntityA.class, 1l);
System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
System.out.println("is element atached? :" + genericDAO.isAtached(entityA));
//this.loadData();
}
public void loadData(){
System.out.println(TransactionIndicatingUtil.getTransactionStatus(true));
System.out.println("is element atached? :" + genericDAO.isAtached(currentCompany));
System.out.println(entityA.getBss.size());
}
}
and a Simple test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "applicationContext.xml" })
#WebAppConfiguration
public class EntityQueryTest {
// #Autowired
// private SessionFactory sessionFactory;
#Autowired
GenericTestBean genericTestBean;
#Test
public void consultarCompania(){
genericTestBean.testQuery();
genericTestBean.loadData();
}
what Im guessin that should happen is:
1. GenericTestBean gets instantiated
2. testQuery is called from outside the proxy starting the transaction
2. loadData is called, the proxy sees the active transaction, and takes the existent resources
3. the data is retrieived
4. The transacion is closed...
But this doesn't happens, there seems to be two different transactions in each method call, and the entity gets detached between calls, issuing a lazy init exception.
the actual output log is this:
bean creado! --here the object get created
Hibernate: select company0_.companyId as ..... --here the first query get executed
[com.pe.controlLines.data.dao.GenericTestBean.testQuery] --here we check the name for the transaction
is element atached? :true --and see if the element is attached to the session
[com.pe.controlLines.data.dao.GenericTestBean.loadData] --this is in the second method call (with a different transaction name :O )
is element atached? :false --both now, the same element get detached
I tried re-attaching the entity, but this gives me a new query to the database (a new query to table EntityA is sent plus the query to get the objects, which I really don't like).
Im hoping to save one additional query just in order to have lazy loading, or does it have to be this way?, or maybe I have some configuration wrong?
Pdta: I think that the view filter option is even worst than the re-attaching option, it could lead to serious performance issues under high concurrency.
Can anyone please clarify the behavior of transaction contexts between methods calls, and how it get related to the session and the state of the entities?
the TransactionIndicatingUtil implementation is taken from here http://java.dzone.com/articles/monitoring-declarative-transac?page=0,1
and the generic dao is build after this idea
General or specific DAO to record delivery with information from multiple tables?
Update
in case is of some use, here is the spring config file
<context:component-scan base-package="xxxxxx" />
<context:annotation-config />
<context:spring-configured />
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- Data Source Declaration -->
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xxxx" />
<property name="username" value="xxxxx" />
<property name="password" value="xxxxx" />
<property name="initialSize" value="2" />
<property name="minIdle" value="0" />
<property name="minEvictableIdleTimeMillis" value="120000" />
<property name="maxActive" value="20" />
<property name="maxWait" value="5000" />
</bean>
<!-- Session Factory Declaration <bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> -->
<!-- Session Factory Declaration -->
<bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan">
<list>
<value>com.xx.xx.xx.xx</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.search.default.directory_provider">filesystem</prop>
<prop key="hibernate.search.default.indexBase">C:/DEVELOPMENT/lucene/indexes</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Transaction Manager is defined -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory"/>
</bean>
The Test class should be transactional too
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "applicationContext.xml" })
#Transactional // <--- add
public class EntityQueryTest {
I am assuming that your applicationContext.xml file is the XML code shown in your post
The JUnit test itself is not transactional. Each method of your GenericTestBean bean is transactional. So, each time the non-transactional test calls a method of the transactional bean, a transaction is started, the bean method is executed, and the transaction is committed. Since you call two transactional methods successively, so two separate transactions are started.
If the test method itself was transactional, then a transaction would be started for the test method, and (by default), the two bean methods would execute in the context of the existing transaction, started by the test. The transaction would commit after the test method has returned.
I'm trying to setup entity manager with Spring 4 and I always get NullPointerException when I try to inject EntityManager with #PersistenceContext annotation.
I have Maven web application. Here's my applicationContext.xml configuration
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="EcommercePU">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.mysite.ecommerceapp.domain</value>
<value>com.mysite.ecommerceapp.domain.*</value>
<value>com.mysite.ecommerceapp.domain.*.*</value>
<value>com.mysite.ecommerceapp.domain.*.*.*</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/ecommercedb" />
<property name="username" value="postgres" />
<property name="password" value="test" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
applicationContext.xml is located under WEB-INF folder. Because I use NetBeans 8 I added Spring Framework support to my project from project properties -> Frameworks. I'm using EntityManager injection with file called GenericDaoImpl and here's it's code:
public abstract class GenericDaoImpl<E extends EntityClass> implements GenericDao<E> {
private Class<E> entityClass;
#PersistenceContext()
private EntityManager entityManager;
//Constructor
public GenericDaoImpl(final Class<E> entityClass) {
this.entityClass = entityClass;
}
//Getters and Setters
public Class<E> getEntityClass() {
return entityClass;
}
public void setEntityClass(final Class<E> entityClass) {
this.entityClass = entityClass;
}
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
public void checkEntityManager() {
System.out.println("em: " + this.entityManager);
}
}
I have one test file where I simply print entity manager with checkEntityManager() method. Whenever I run it I always get null value for EntityManager. What could be wrong? My biggest doubt is that my applicationContext.xml is in wrong place or it is not used anywhere and thus it can't find configuration properties in applicationContext. I have tested moving applicationContext.xml file to resources folder but it didn't helped either. Other questions that I also have are following:
Do I need to have persistence.xml? Since I use Spring 4 with packagesToScan feature I heard that persistence.xml is not required but I'm not sure.
Is it wise to use hibernate to take care only basic entities cruds and other dao queries with JdbcTemplate?
All help would be appreciated.
I finally solved the problem and there were lots of things that has to be done.
When I tested my Entity Manager through JUnit tests I got NullPointerException and reason was the configuration file was incorrect folder.
applicationContext.xml was properly setup except there was a small problem that messed the whole file and that was <property name="persistenceUnitName" value="EcommercePU">. Because I didn't had such persistence unit file in whole project it couldn't find it. When you add that property it doesn't mean that you have created a spring configuration file that has such persistence unit name. It simply means that if you want to provide persistence configurations to your LocalContainerEntityManagerFactory you would refer with that name to your persistence unit. This is not required in Spring 4.
applicationContext.xml had to be moved from WEB-INF to resources folder.
When you would run JUnit tests you should use #Autowired annotation to annotate DAO's.
Dao implementation classes should have #Repository annotation.
#Transactional annotation is required at least for CRUD methods if you are going to use. You can also annotate whole class. If you don't add #Transactional annotation EntityManager wouldn't execute persist, remove, update, find and other methods properly. Remember this is required if you are using Spring configurations.
I need to do very similar thing to what is described in Injecting Entitymanager via XML and not annnotations, but I need to inject from XML the real, container-created, entity manager, so that it behaves exactly as if there is a real #PersistenceContext annotation. I've found a LocalEntityManagerFactoryBean (notice missing "Container" word), but I'm affraid that it creates a new entity manager factory and therefore entity manager won't be compatible with that injected via real #PersistenceContext annotation.
I will describe the reason, because it is weird and maybe the solution to my problem is to choose completely different approach. I'm using PropertyPlaceholderConfigurer in my spring configuration and in this configurer I'm referencing other beans. I'm experiencing a bug that autowiring doesn't work in those referenced beans. I don't know why and how PropertyPlaceholderConfigurer turns off autowiring in those referenced beans but the fact is, that if I replace autowiring by xml configuration for those beans, everything works. But I'm unable to replace autowiring of EntityManager, since it's not standard spring bean, but jndi-loaded something I don't fully understand.
One way or the other, is there some solution?
in spring-bean.xml ,
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="USER_TEST"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
</props>
</property>
<bean id="PersonDao" class="com.xxx.java.person.persistence.PersonDAO">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="earlyInitializedApplicationSettingsService" class="...services.impl.ApplicationSettingsServiceImpl" autowire-candidate="false">
<property name="applicationSettingsDao">
<bean class="....impl.ApplicationSettingsDaoImpl">
<property name="entityManager">
<bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/persistence/somePersistenceUnit"/>
</bean>
</property>
</bean>
</property>
</bean>
</property>
</bean>
Notice mainly the fact, that I'm not using standard jee:jndi-lookup, because it didn't work (in the conditions created by PropertyPlaceholderConfigurer) and that was the source of my confusion. When I used direct JndiObjectFactoryBean, it worked.
I understand that this is a very long question, but i wanted to ask everything because i'm
stuck with these things for more than 2 weeks and i'm in a situation to solve this within
this week. Please guide me in this matter.
I'm Using EclipseLink jpa version 2, Spring 3, jdk6, MySQL5 and tomcat7.
I have configured the following in each of my DAO classes.
#PersistenceContext
private EntityManager em;
I have the following in my Spring xml:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="url" value="jdbc:mysql://localhost:3306/xxxxx"/>
<property name="username" value="xxxx"/>
<property name="password" value="xxxx"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" >
<property name="showSql" value="true"/>
<property name="generateDdl" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
From Persistence.xml:
<persistence-unit name="xxxxx" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<-- class mappings -->
</persistence-unit>
I've got few confusion about what i have done:
Is the EntityManager injected by Spring? (I understand that #PersistenceContext is a
J2EE annotation, so wondering whether it is injected without Spring's contribution).
As i have already mentioned, i have injected EntityManager in all the DAO classes. Is
this a good practice? or should i make it Singleton by having a separate class like
PersistenceManager, which has EntityManager attribute wired, and have
getEntityManager() method?
As you can see above, i have configured Spring transactions. But when i do CRUD
operations continuously for 2-3 times, application gets stuck and fails with EclipseLink
exception saying unable to get lock, timeout etc. Am i doing anything wrong here or
missing any transaction configurations??
With the above configurations, i can only use #Transactional annotation with default
values which are PROPAGATION_REQUIRED,ISOLATION_DEFAULT. If i change these for any other
values, such as #Transactional(PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE) etc,
application throws exception as Custom isolation levels are not supported. Again, am
i missing any configurations?
Thanks.
Yes, spring recognizes the #PersistenceContext annotation and injects the entity manager
Spring takes care of that - it injects the same EntityManager instance in all DAOs. In fact, it injects a proxy so that each request uses a different entity manager.
Normally everything should run fine. You need <tx:annotation-driven /> in order to use #Transactional
JPA only supports the default isolation level. You can work this around by customizing the spring jpa dialect, but there's nothing built-in. The way to go is extend XJpaDialect (in your case X=EclipseLink), override the beingTransaction, obtain the Connection (in an eclipse-link specific way), set the desired isolation level (accessible through the transaction definition), and configure this as a property of your LocalContainerEntityManagerFactoryBean:
<property name="jpaDialect">
<bean class="com.foo.util.persistence.EclipseLinkExtendedJpaDialect" />
</property>
In my project I use Hibernate with programmatic transaction demarcation.
Every time in my Service methods i write something similar to this.
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
.. perform operation here
session.getTransaction().commit();
Now I'm going to refactor my code with declarative transaction management. What I got now ...
<context:component-scan base-package="package.*"/>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="mySessionFactory"/>
</property>
</bean>
Service class:
#Service
public class TransactionalService {
#Autowired
private SessionFactory factory;
#Transactional
public User performSimpleOperation() {
return (User)factory.getCurrentSession().load(User.class, 1L);
}
}
And simple test -
#Test
public void useDeclarativeDem() {
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("spring-config.xml");
TransactionalService b = (TransactionalService)ctx.getBean("transactionalService");
User op = b.performSimpleOperation();
op.getEmail();
When I try to get user email outside of Transactional method, I got lazy initialization exception, email is my case is a simple string. Hibernate does not even perform sql query, until I call any getters on my POJO.
what I am doing wrong here?
Is this approach valid?
Can you suggest any opensources project which works on spring/hibernate with annotation based configuration?
Update
For some reason if I replace getCurrentSession with openSession this code works fine. Can someone explain it please?
Ok, finally i realized what was the problem. In code above i used load instead of get. Session.load did not actually hit the databased. That's the reason why i get lazy-initialization exception outside of #Transactional method
If i use openSession instead of getCurrentSession, session is opened outside of scope spring container. As result session was not close and it allow me to read object properties outside of #Transactional method
The reason Hibernate does not perform any SQL queries until you call the getters is because I believe the FetchType is set to LAZY. To fix this problem you will need to change the FetchType to EAGER in your POJO:
#Entity
#Table(name = "user")
public class User {
/*Other data members*/
#Basic(fetch = FetchType.EAGER)
private String email;
}
I personally never had to specify Basic types to have an EAGER FetchType so I'm not entirely sure why your configuration requires this. If its only in your tests it could be due to the way you have your JUnit tests configured. It should have something like this on the class declaration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"/test-app-config.xml"})
#Transactional
public class UserServiceTest {
}
As for a good resource I always find SpringByExample to be helpful.
EDIT
So I'm not entirely sure what is wrong with your configuration. It does differ from the way I have mine set up so here is my typical configuration in hopes that it helps. The hibernate.transaction.factory_class could be a key property you are missing. I also use the AnnotationSessionFactoryBean:
<!-- DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost/dbname"
p:username="root"
p:password="password"/>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="com.beans"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
</props>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
From Hibernate documentation https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch11.html#objectstate-loading:
Be aware that load() will throw an unrecoverable exception if there is no matching database row. If the class is mapped with a proxy, load() just returns an uninitialized proxy and does not actually hit the database until you invoke a method of the proxy. This is useful if you wish to create an association to an object without actually loading it from the database. It also allows multiple instances to be loaded as a batch if batch-size is defined for the class mapping.
From above documentation in your case bean is mapped with spring proxy so load just returns. Hence you need to use get() instead of load() which always hits the database.