Why is Spring's Transaction Management not working with this configuration? - java

There are terribly many questions about this on SO, but I've tried some of them that sound correct, but I'm still getting
org.hibernate.HibernateException: No Session found for current thread
My Service layer classes are annotated as such:
#Service
public class MyService {
#Autowired
public SomeDao someDao;
#Transactional
public void performSomeTransaction() {/* ... */}
}
My application context XML has the following relevant declarations:
<context:component-scan base-package = "com.myapp.business.dao.impl" />
<context:component-scan base-package = "com.myapp.business.services" />
<context:annotation-config />
<tx:annotation-driven transaction-manager = "transactionManager" />
<!-- Hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="connection.url">jdbc:mysql://localhost:3306/bidapp</prop>
<prop key="connection.username">bidapp</prop>
<prop key="connection.password">pennyfss</prop>
<prop key="connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.pool_size">10</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="c3p0.acquireIncrement">1</prop>
<prop key="c3p0.max_size">50</prop>
<prop key="c3p0.max_statement">0</prop>
<prop key="c3p0.min_size">10</prop>
<prop key="c3p0.timeout">0</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<list>
<value>com.bidapp.business.domain</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/bidapp" />
<property name="username" value="bidapp" />
<property name="password" value="pennyfss" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I also have my dispatcher-servlet.xml file with
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<context:component-scan base-package="com.myapp.presentation.controllers" />
<context:annotation-config />
<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
Why doesn't spring wrap my services with transactions?
So it appears that the issue has to do with not getting instances correctly. I have the following Shiro Security config:
<bean id = "hibernateRealm" class = "com.bidapp.presentation.shiro.HibernateRealm" >
<property name = "credentialsMatcher" ref = "credentialsMatcher" />
</bean>
<bean id = "credentialsMatcher" class = "com.bidapp.presentation.shiro.JasyptCredentialsMatcher" />
<bean id = "securityManager" class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name = "realm" ref = "hibernateRealm" />
</bean>
HibernateRealm is the service class with the #Transactional annotation. Shouldn't Spring be wrapping it in a proxy since it is creating it here.

The most common causes of this problem are
Incorrectly obtaining a service instance: for instance, instantiating it yourself rather than getting an instance from Spring.
Incorrectly configuring the root and child application contexts in a Spring MVC application. I've answered quite a number of these questions here. Here are some of the more educational ones:
Spring XML file configuration hierarchy help/explanation
Declaring Spring Bean in Parent Context vs Child Context
Showing the code where you obtain and use the service instance will help define the problem.

Add the property hibernate.current_session_context_class=thread during session factory creation in hibernate-persistance.xml file it will work.

Related

Inject 2 (3 in the near future) different entityManagerFactory (or entityManager) in spring application

I have Spring + JPA (Hibernate) project, at which i connect to MsSQL database, now i need to open a new connection but this time it will be for MySQL.
i am using XML configuration
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${spring.datasource.driverClassName}" />
....
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:packagesToScan="com.wsg.admin.api.model"
p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter">
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
....
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Configure the MySQL connection -->
<bean id="enduserDataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${enduser.db.driver}" />
....
</bean>
<bean id="enduserEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="enduserDataSource" p:packagesToScan="com.wsg.admin.api.model"
p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter">
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
....
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="enduserTransactionManager" />
<bean id="enduserTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="enduserEntityManagerFactory" />
</bean>
then i try to inject the entityManager using the fragment
#Autowired
EntityManager entityManager;
but i get exception
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'brandServiceImpl': Unsatisfied dependency expressed through field 'entityManager'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected single matching bean but found 2: org.springframework.orm.jpa.SharedEntityManagerCreator#0,org.springframework.orm.jpa.SharedEntityManagerCreator#1
Since you have two Entity Manager's(From EntityMangaerFactory) you need to tell spring which specifix EntityManager you want to be Autowired. Use #Qualifier
#Autowired
#Qualifier("enduserEntityManagerFactory") // use bean id of the Entity Manager Factory you want to inject
EntityManagerFactory entityManagerFactory
EntityManager entityManager = entityManagerFactory.createEntityManager();
More about this here
Fixed. Thanks to #Volceri
i used the answer https://stackoverflow.com/a/18073628/1973933, as follow
add <property name="persistenceUnitName" value="appPU" /> to each of entityManagerFactory
<bean id="entityManagerFactory" ... >
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
...
</props>
</property>
<property name="persistenceUnitName" value="dataSourcePU" />
</bean>
<bean id="endUserEntityManagerFactory" ... >
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
...
</props>
</property>
<property name="persistenceUnitName" value="enduserDataSourcePU" />
</bean>
and to inject the em objects, i used
#PersistenceContext(unitName="dataSourcePU")
EntityManager entityManager;
#PersistenceContext(unitName="enduserDataSourcePU")
EntityManager endUserEntityManager;

Spring hibernate transactional removing entity

I have Spring MVC application divided on layers. One of them is Service and here's one of the methods
#Transactional
public boolean deleteProject(long id){
Project project = projectDAO.read(id);
taskDAO.deleteAllByProject(project);
projectDAO.delete(project);
return true;
}
It deletes tasks, but project remains in the db (with no error or exception). I didnt use #Transactional in repository classes.
Here's my Spring config
<?xml version="1.0" encoding="UTF-8"?>
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost:5432/automate" />
<property name="username" value="postgres" />
<property name="password" value="" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="ru.jeak.keep" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="connection.pool_size">3</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.default_schema">test</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="userHibernateDAO" class="ru.jeak.keep.repository.hibernate.UserHibernateDAO" />
<bean id="projectHibernateDAO" class="ru.jeak.keep.repository.hibernate.ProjectHibernateDAO" />
<bean id="taskHibernateDAO" class="ru.jeak.keep.repository.hibernate.TaskHibernateDAO" />
UPDATE
I added persistence #Transactional to DAO class and it works now. But Im still confused why Spring did not do the rollback of deleting tasks after failure of deleting project

Error No Session found for current thread when trying to save into two database simultaneously

Hi i'm trying to save into two database simultaneously but I always get an error.
Exception in thread "main" org.hibernate.HibernateException: No Session found for current thread
here's my code :
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false)
public void save(ArsenalPlayer domain1, ArsenalPlayer2 domain2)
throws Exception {
dao1.save(domain1);
dao2.save(domain2);
}
dao1 uses a sessionFactory attached to datasource1
dao2 uses a sessionFactory attached to datasource2
and here's my configuration
DataSource
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/arsenal" />
<property name="user" value="root" />
<property name="password" value="ahmids" />
</bean>
SessionFactory
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">update</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.gongfu4.bean.ArsenalPlayer</value>
</list>
</property>
</bean>
DataSource2
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/arsenal2" />
<property name="user" value="root" />
<property name="password" value="ahmids" />
</bean>
SessionFactory2
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">update</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.gongfu4.bean.ArsenalPlayer2</value>
</list>
</property>
</bean>
applicationContext
<context:component-scan base-package="com.gongfu4" />
<context:annotation-config />
<import resource="dataSource.xml" />
<import resource="dataSource2.xml" />
<import resource="hibernate.xml" />
<import resource="hibernate2.xml" />
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="myTx"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
and here are my dao classes :
DAO1
#Autowired
SessionFactory sessionFactory;
public void save(ArsenalPlayer domain) {
sessionFactory.getCurrentSession().save(domain);
}
DAO2
#Autowired
SessionFactory sessionFactory2;
public void save(ArsenalPlayer2 domain) {
sessionFactory2.getCurrentSession().merge(domain);
}
Is there something wrong with my configuration?
You cannot use those two transaction managers like that. You have two data sources, two transaction managers and, from your code, I understand that you want the two save operations to be performed in the same transaction. The question is "a transaction from which transaction manager?".
The way you have the code and the configuration, Spring will use the "default" transaction manager because <tx:annotation-driven/> by default will search for a transaction manager bean with the id "transactionManager" and the bean with this id is the one for data source dataSource. But your code is not working and this is the expected behavior. Spring will open a Hibernate session using sessionFactory and the dao1.save(domain1); call will succeed because this is the correct Hibernate session for the correct dataSource. But when the dao2.save(domain2); method is called you will have the same session from dao1 call but be used for a db operation for the second database.
As I see it you have two options:
Use a JTA transaction manager to coordinate the two datasources. With a JTA the two save operations will be atomic. If one fails, then both are rolled back.
Perform the two save(domain) operations in two different transactions properly configuring the #Transactional annotation to use the correct transaction manager. In this case, the two save operations will not be atomic. If one save fails then only that one will be rolled-back. See below an exempt taken from the Spring reference documentation here:
public class TransactionalService {
#Transactional("order")
public void setSomething(String name) { ... }
#Transactional("account")
public void doSomething() { ... }
}
<tx:annotation-driven/>
<bean id="transactionManager1" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>
Your current configuration doesn't support global transactions (XA) and therefore you can't span one Transaction on two different databases.
For this reason you need two Hiberante transaction managers, one for each session factory. Then you need to instruct the transactional service which transaction manager should be used.
So instead of:
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false)
public void save(ArsenalPlayer domain1, ArsenalPlayer2 domain2)
throws Exception {
dao1.save(domain1);
dao2.save(domain2);
}
you should have:
<bean id="txManager1" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<bean id="txManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false, value="txManager1")
public void save(ArsenalPlayer domain1)
throws Exception {
dao1.save(domain1);
}
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false, value="txManager2")
public void save(ArsenalPlayer domain2)
throws Exception {
dao2.save(domain2);
}

Obtaining a sessionFactory in hibernate

I just created two small crud applications one is a web application and the other I am running from a main method.
I am confused about how the sessionFactory object is being obtained in both the applications.
In my web application in DAOImpl I am just injecting the sessionFactory object and doing
#Repository
public class ContactDaoImpl implements ContactDao {
#Autowired
private SessionFactory sessionFactory;
public void addContact(Contact contact) {
//save: Persist the given transient instance
sessionFactory.getCurrentSession().save(contact);
}
My Spring Application Context
<!-- <context:property-placeholder> XML element automatically registers a new PropertyPlaceholderConfigurer
bean in the Spring Context. -->
<context:property-placeholder location="classpath:database.properties" />
<context:component-scan base-package="com.contactmanager"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<!-- View Resolver Configured -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!-- Creating DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<!-- To persist the object to database, the instance of SessionFactory interface is created.
SessionFactory is a singleton instance which implements Factory design pattern.
SessionFactory loads hibernate.cfg.xml and with the help of TransactionFactory and ConnectionProvider
implements all the configuration settings on a database. -->
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<!-- Configuring Hibernate Transaction Manager -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
But in the other application In which I don't use Spring I only use hibernate. I have to get the sessionFactory from annotationConfiguration then open the session and begin transaction.
AnnotationConfiguration().configure().buildSessionFactory();
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("4715");
stock.setStockName("GENM");
session.save(stock);
session.getTransaction().commit();
Can anyone tell me why I do have to written more lines of code to persist an object here. Is the Spring configuration doing everything in the first application?
This part of your Spring configuration is configuring the sessionFactory bean:
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
You can read more about setting up the Hibernate session factory with Spring here
This part of your DAO code is responsible for asking Spring to inject the session factory:
#Autowired
private SessionFactory sessionFactory;
You can read more about autowiring in Spring here

Get Dialect within some class inside Spring MVC + Hibernate application

I have Hibernate Transaction manager configured inside Spring MVC controller.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://127.0.0.1/doolloop2" />
<property name="username" value="doolloop2" />
<property name="password" value="doolloop" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingLocations">
<list>
<value>WEB-INF/mapping/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
In Addition, I have some class which needs to get Hibernate Dialect inside on of it method.
Is class is not Configured as bean inside Spring Framework.
How can I access Hibernate Dialect property from this class? I believe it should be some static class,but I don't know how can I do it. Please help.
You could separate the properties from the spring config. Put them in a properties file, then reference that in a PropertyPlaceholderConfigurer bean ( http://almaer.com/blog/spring-propertyplaceholderconfigurer-a-nice-clean-way-to-share ). Then you could inject that value into whatever bean it is that you need the value in the same way you are injecting it into the sessionFactory bean.

Categories

Resources