Transaction is not being rollbacked in spring - spring

While issuing two inserts, if second one is failed the transaction should be rollback but this is not happening in my case, following are the details of configuration!
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.xyz.model.Merchant</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.format_sql">${hibernate.format_sql}</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allServices"
expression="execution(*
com.xyz.services.DemoApiServiceImpl.saveEmployee(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allServices"/>
</aop:config>
<aop:aspectj-autoproxy/>
and these are the code details;
#Service
#Transactional
public class DemoApiServiceImpl implements DemoApiService {
#Override
//#Transactional( propagation = Propagation.REQUIRED, rollbackFor = Exception.class )
public boolean saveEmployee(Employee employee) throws Exception {
Boolean flag = Boolean.FALSE;
flag = demoApiDao.saveOrUpdateEmployee(employee);
if(flag)
//generating exception so that above insert should rollback!
throw new Exception("ok");
if(!CollectionUtils.isEmpty(employee.getUsers())) {
Users user = (Users) employee.getUsers().toArray()[0];
//sendEmail(user,EmailType.USER_SIGN_UP.name(),Constants.MAIL_SUBJECT_ACTIVATION_LINK);
UsersDto usersDto = new UsersDto();
usersDto.setActivationCode(user.getActivationCode());
String emailText = Utils.createEmailText(usersDto, EmailType.USER_SIGN_UP.name());
Utils.sendEmail(user.getUsername(), Constants.FROM_EMAIL, Constants.MAIL_SUBJECT_ACTIVATION_LINK, emailText);
}
return flag;
}
}
unfortunately the transaction is not being rollbacked, I have generated exception manually to reverse the transaction.
Any help in this regards?
TA.

Related

Spring Hibernate transaction committing but not saving in DB

Using Spring Boot, declarative transaction management.
Find operation is working fine but save is not reflecting changes in DB.
Please let me know if any more information is required.
this.getCurrentSession().saveOrUpdate(entity);
Spring Boot configuration:
#SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class,
TransactionAutoConfiguration.class,
WebSocketAutoConfiguration.class})
RDBM persistence beans definition:
<bean name="transactionAgnosticDataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="url" value="${spring.datasource.url}"/>
<property name="username" value="${spring.datasource.username}"/>
<property name="password" value="${spring.datasource.password}"/>
<property name="driverClassName" value="org.mariadb.jdbc.Driver"/>
<property name="jmxEnabled" value="false"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnConnect" value="true"/>
<property name="testWhileIdle" value="false"/>
<property name="testOnReturn" value="false"/>
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="validationQueryTimeout" value="5"/>
<property name="validationInterval" value="30000"/>
<property name="maxActive" value="50"/>
<property name="maxIdle" value="30"/>
<property name="initialSize" value="20"/>
</bean>
<bean name="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource" ref="transactionAgnosticDataSource"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>com.test.xyz.persistence.model.AlertOptImpl</value>
<value>com.test.xyz.persistence.model.ChallengeImpl</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>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="find*" read-only="true" rollback-for="java.lang.Throwable"/>
<tx:method name="*" rollback-for="java.lang.Throwable"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* com.test.xyz.core.service.*ServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
</aop:config>
Service method:
#Override
public void test() {
TestResource testResource = testResourceDao.findById(1l).get();
testResource.setPosition(7);
testResource.save(testResource); //this calls this.getCurrentSession().saveOrUpdate(entity);
//testResource.flushSession();
}
Not getting any errors. Noticed the following in debug log:
o.s.o.h.HibernateTransactionManager : Initiating transaction commit
o.s.o.h.HibernateTransactionManager : Committing Hibernate transaction on Session
o.s.jdbc.datasource.DataSourceUtils : Resetting read-only flag of JDBC Connection [Transaction-aware proxy for target Connection
o.s.o.h.HibernateTransactionManager : Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey
o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [[com.
o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
o.s.web.servlet.DispatcherServlet : Successfully completed request

How to configure Two Data Sources to single Transaction manager using Spring JTA,So that on the exception Both of the data sources get rolled back

I would like to configure the two Data sources one is Oracle and one is My-SQL to the Transaction Manager in the Spring JTA to perform the 2 phase commit so that any one transaction of the any of the Data sources get failed and the spring JTA needs to perform the roll back on the both of the data sources
*Heard the atomikos can we used to configure this kind of scenarios
Please provide the some configuration codes are anything that would be useful in implementing this code *
Git url for the entire code:
https://github.com/mageshsrinivasulu/poc
spring-beans.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean class="org.springframework.beans.factory.config
.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:Application.properties" />
</bean>
<bean id="oracleSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="oracleDataSource" />
<property name="mappingResources">
<list>
<value>persons.hbm.xml </value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.autocommit">false</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
</props>
</property>
</bean>
<bean id="mysqlSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="mysqlDataSource" />
<property name="mappingResources">
<list>
<value>persons.hbm.xml </value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.autocommit">false</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
</props>
</property>
</bean>
<!-- Creating TransactionManager Bean, since JDBC we are creating of type
DataSourceTransactionManager -->
<bean id="oracleTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="oracleDataSource" />
</bean>
<bean id="mysqlTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="mysqlDataSource" />
</bean>
<bean id="oracleDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${oracle.hibernate.connection.driver_class}" />
<property name="url" value="${oracle.hibernate.connection.url}" />
<property name="username" value="${oracle.Username}" />
<property name="password" value="${oracle.Password}" />
</bean>
<bean id="mysqlDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql.jdbc.driverClassName}" />
<property name="url" value="${mysql.hibernate.connection.url}" />
<property name="username" value="${mysql.Username}" />
<property name="password" value="${mysql.Password}" />
</bean>
<bean id="persons" class="com.bnym.aal.poc.spring_jta.Persons">
</bean>
<bean id="App" class="com.bnym.aal.poc.spring_jta.App">
<property name="springJtaDaoClass" ref="springJtaDaoClass" />
</bean>
<bean id="springJtaDaoClass" class="com.bnym.aal.poc.spring_jta.springJtaDaoClass">
<property name="oracleSessionFactory" ref="oracleSessionFactory" />
<property name="mysqlSessionFactory" ref="mysqlSessionFactory" />
<property name="oracleTransactionManager" ref="oracleTransactionManager" />
<property name="mysqlTransactionManager" ref="mysqlTransactionManager" />
<property name="persons" ref="persons" />
</bean>
springJtaDaoClass
import java.io.Serializable;
import java.util.List;
import javax.sql.DataSource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
package com.bnym.aal.poc.spring_jta;
public class springJtaDaoClass implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private static SessionFactory oracleSessionFactory;
private static SessionFactory mysqlSessionFactory;
private HibernateTemplate oracleJdbcTemplateObject;
private HibernateTemplate mysqlJdbcTemplateObject;
private static Persons persons;
public static SessionFactory getOracleSessionFactory() {
return oracleSessionFactory;
}
public void setOracleSessionFactory(SessionFactory oracleSessionFactory) {
springJtaDaoClass.oracleSessionFactory = oracleSessionFactory;
this.oracleJdbcTemplateObject=new HibernateTemplate(oracleSessionFactory);
}
public static SessionFactory getMysqlSessionFactory() {
return mysqlSessionFactory;
}
public void setMysqlSessionFactory(SessionFactory mysqlSessionFactory) {
springJtaDaoClass.mysqlSessionFactory = mysqlSessionFactory;
this.mysqlJdbcTemplateObject=new HibernateTemplate(mysqlSessionFactory);
}
public static PlatformTransactionManager oracleTransactionManager;
public static PlatformTransactionManager mysqlTransactionManager;
public static PlatformTransactionManager getOracleTransactionManager() {
return oracleTransactionManager;
}
public static void setOracleTransactionManager(PlatformTransactionManager
oracleTransactionManager) {
springJtaDaoClass.oracleTransactionManager = oracleTransactionManager;
}
public static PlatformTransactionManager getMysqlTransactionManager() {
return mysqlTransactionManager;
}
public static void setMysqlTransactionManager(PlatformTransactionManager
mysqlTransactionManager) {
springJtaDaoClass.mysqlTransactionManager = mysqlTransactionManager;
}
public static Persons getPersons() {
return persons;
}
public static void setPersons(Persons persons) {
springJtaDaoClass.persons = persons;
}
public void dbOracleAccess()
{
TransactionDefinition oracledef= new DefaultTransactionDefinition();
TransactionStatus oraclestatus =
oracleTransactionManager.getTransaction(oracledef);
try
{
Persons person1=getPersons().persons(1,"a","b","c","d");
oracleJdbcTemplateObject.save(person1);
oracleTransactionManager.commit(oraclestatus);
}
catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
oracleTransactionManager.rollback(oraclestatus);
throw e;
}
}
public void dbMySqlAccess()
{
TransactionDefinition mysqldef= new DefaultTransactionDefinition();
TransactionStatus
mysqlstatus=mysqlTransactionManager.getTransaction(mysqldef);
try
{
Persons person2=getPersons().persons(2,"e","b","c","d");
mysqlJdbcTemplateObject.save(person2);
mysqlTransactionManager.commit(mysqlstatus);
}
catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
mysqlTransactionManager.rollback(mysqlstatus);
throw e;
}
}
}
Below is the working code of the above stated issue:
Entire project for the Atomikos Transaction manager for the connecting the two data sources to the single transaction manager by out of box integration would be available in the below GIT url
https://github.com/mageshsrinivasulu/spring-jta.git
spring-beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:Application.properties" />
</bean>
<bean id="oracleSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="oraclesDataSource" />
<property name="mappingResources">
<list>
<value>persons.hbm.xml </value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<!-- <prop key="hibernate.autocommit">true</prop> <prop key="hibernate.connection.isolation">3</prop> -->
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.CMTTransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
</props>
</property>
</bean>
<bean id="mysqlSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="mysqlDataSource" />
<property name="mappingResources">
<list>
<value>persons.hbm.xml </value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- <prop key="hibernate.autocommit">ture</prop> <prop key="hibernate.connection.isolation">3</prop> -->
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.CMTTransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">10</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
</props>
</property>
</bean>
<tx:annotation-driven proxy-target-class="true" />
<tx:jta-transaction-manager
transaction-manager="atomikosTransactionManager" />
<tx:annotation-driven transaction-manager="atomikosTransactionManager"
proxy-target-class="true" />
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
<property name="transactionTimeout" value="300" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="atomikosTransactionManager,atomikosUserTransaction">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<bean id="mysqlDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>mySqlDataSource</value>
</property>
<property name="xaDataSourceClassName">
<value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="databaseName">sys</prop>
<prop key="serverName">localhost</prop>
<prop key="port">3306</prop>
<prop key="user">root</prop>
<prop key="password">magesh123</prop>
<prop key="url">jdbc:mysql://localhost:3306/sys</prop>
</props>
</property>
<property name="minPoolSize">
<value>1</value>
</property>
</bean>
<bean id="oraclesDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName">
<value>OracleDataSource</value>
</property>
<property name="xaDataSourceClassName">
<value>oracle.jdbc.xa.client.OracleXADataSource</value>
</property>
<property name="xaProperties">
<props>
<prop key="databaseName">XE</prop>
<prop key="serverName">localhost</prop>
<!-- <prop key="port">1521</prop> -->
<prop key="user">system</prop>
<prop key="password">magesh123</prop>
<prop key="URL">jdbc:oracle:thin:#localhost:1521:XE</prop>
</props>
</property>
<property name="minPoolSize">
<value>1</value>
</property>
</bean>
<bean id="persons" class="com.bnym.aal.poc.spring_jta.Persons">
</bean>
<bean id="App" class="com.bnym.aal.poc.spring_jta.App">
<property name="springJtaDaoClass" ref="springJtaDaoClass" />
</bean>
<bean id="springJtaDaoClass" class="com.bnym.aal.poc.spring_jta.springJtaDaoClass">
<property name="oracleSessionFactory" ref="oracleSessionFactory" />
<property name="mysqlSessionFactory" ref="mysqlSessionFactory" />
<property name="atomikosTransactionManager" ref="transactionManager" />
<property name="persons" ref="persons" />
</bean>
springJtaDaoClass.java
package com.bnym.aal.poc.spring_jta;
import java.io.Serializable;
import org.hibernate.FlushMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class springJtaDaoClass implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static SessionFactory oracleSessionFactory;
private static SessionFactory mysqlSessionFactory;
private HibernateTemplate oracleJdbcTemplateObject;
private HibernateTemplate mysqlJdbcTemplateObject;
private static Persons persons;
public static SessionFactory getOracleSessionFactory() {
return oracleSessionFactory;
}
public void setOracleSessionFactory(SessionFactory oracleSessionFactory) {
springJtaDaoClass.oracleSessionFactory = oracleSessionFactory;
this.oracleJdbcTemplateObject = new
HibernateTemplate(oracleSessionFactory);
}
public static SessionFactory getMysqlSessionFactory() {
return mysqlSessionFactory;
}
public void setMysqlSessionFactory(SessionFactory mysqlSessionFactory) {
springJtaDaoClass.mysqlSessionFactory = mysqlSessionFactory;
this.mysqlJdbcTemplateObject = new
HibernateTemplate(mysqlSessionFactory);
}
public static PlatformTransactionManager atomikosTransactionManager;
public static PlatformTransactionManager getAtomikosTransactionManager() {
return atomikosTransactionManager;
}
public static void setAtomikosTransactionManager(PlatformTransactionManager
atomikosTransactionManager) {
springJtaDaoClass.atomikosTransactionManager =
atomikosTransactionManager;
}
public static Persons getPersons() {
return persons;
}
public static void setPersons(Persons persons) {
springJtaDaoClass.persons = persons;
}
#Transactional()
public void daoWrapper() throws Exception {
atomikosTransactionManager = getAtomikosTransactionManager();
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status =
atomikosTransactionManager.getTransaction(def);
Persons person1 = new Persons();
person1.persons(2, "a", "b", "c", "d");
try {
getMysqlSessionFactory().getCurrentSession().save(person1);
getOracleSessionFactory().getCurrentSession().save(person1);
atomikosTransactionManager.commit(status);
} catch (Exception e) {
System.out.println("Error in creating record, rolling back");
atomikosTransactionManager.rollback(status);
e.printStackTrace();
}
}
}
You can check out mine github link for full sample web application for Two Phase (2PC) Protocol demo which store data in MySQl database first and then in Oracle database and also maintain ACID if oracle database throw exception then roll back is also happen in MySql database
Git hub link for 2PC Sample Web application
Two Phase (2PC) demo application
I am not using 3rd party JTA provider instead i am using J2EE Compliant Application server JBOSS AS 7 for JTA service.

Spring transaction does not start

Environment: Eclipse Keppler, jetty 7.5.1,
Spring 3.2.1, Hibernate 4.2.5, Oracle 11
Problem: hibernate entity saves does not apply to database physically
Cause of problem may be: no active transaction
Question: Why does not transaction start?
Note: if I change openSession() to getCurrentSession(), everything works. Transaction starts & entity saves to DB physically.
GenericDaoImpl:
#Transactional(propagation = Propagation.REQUIRED, readOnly = false,
value = "transactionManager")
public abstract class GenericDaoImpl<T, ID extends Serializable> implements GenericDao<T, ID> {
private Class<T> persistentClass;
protected SessionFactory sessionFactory;
#Override
public T addEntity(T entity) {
Session session = null;
try {
session = sessionFactory.openSession();
session.save(entity);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(session != null){
Transaction t = session.getTransaction();
System.out.println("Transaction().isActive()......." + session.getTransaction().isActive());
System.out.println("before: session.isOpen() " + session.isOpen() + " trx wasCommitted " + t.wasCommitted());
session.close();
System.out.println("after: session.isOpen() " + session.isOpen() + " trx wasCommitted" + t.wasCommitted());
}
}
return entity;
}
UserDaoImpl extending GenericDaoImpl:
#Component
#Scope("prototype")
#Transactional(propagation = Propagation.REQUIRED, readOnly = false, value = "transactionManager")
public class UserDaoImpl extends GenericDaoImpl<User, Long> implements UserDao {
.
.
}
After following code executed called:
userDao.addEntity(user);
logs printed below:
Transaction().isActive().......false
before: session.isOpen() true trx wasCommitted false
after: session.isOpen() false trx wasCommittedfalse
transaction logs:
[2016-07-15 10:42:04,567][DEBUG] Adding transactional method 'addEntity' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'transactionManager'
databaseContext.xml:
<bean class="com.blabla.dao.local.implementations.UserDaoImpl"
scope="prototype" name="userDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan"
value="com.blabla.model.local,com.blabla.model.authorization, com.blabla.model.authentication" />
<property name="entityInterceptor">
<bean class="com.blabla.listeners.EntityInterceptor" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>
<prop key="hibernate.connection.driver_class">${jdbc.driver}</prop>
<prop key="hibernate.connection.url">${jdbc.url}</prop>
<prop key="hibernate.connection.username">${jdbc.user}</prop>
<prop key="hibernate.connection.password">${jdbc.password}</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="5" />
<property name="maxActive" value="10" />
</bean>
In your example it's pretty much obvious that spring handles hibernate session and transaction:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
So you cannot use this:
session = sessionFactory.openSession();
Because you are opening new hibernate session and spring does not know nothing about this.
Using: sessionFactory.getCurrentSession() means that spring will handle everything behind the scene with your proper configuration.

Spring Test transaction not rolling back

Using the spring testing framework, my transactions do not roll back and I have absolutely no idea why. I've spent a good few days trying to find answers on SO but to no avail so I decided to post.
Testfile
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/applicationContextTest.xml")
#Transactional
public class joinTest {
#Autowired
private DAO AccountDAO;//My DAO is annotated with #Repository
#Before
public void beforeMethod()
{
//log4j append code
}
#Test
public void saveMethod()
{
Account acct = new Account();
acct.setUsername("USER");
SmokeEvent evt = new SmokeEvent();
evt.setDateSmoked(new DateTime());
evt.setAccount(acct);
AccountDAO.addSmokeEvent(evt);
}
}
applicationContext.xml
<context:component-scan base-package="com.abstinence.Logic"/>
<context:annotation-config/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://82.165.173.127/testdb"/>
<property name="username" value="SA"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.abstinence.Logic"/>
<property name="hibernateProperties">
<props>
<prop key ="dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="hibernateDAOOperation" expression="execution(* com.abstinence.Logic.AccountDAO.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="hibernateDAOOperation"/>
</aop:config>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I have checked the logs from log4j. The unusual thing is there is no mention of a rollback anywhere. There is a mention of the logs creating a session and inserting the data into the database but nothing about a rollback.
Someone please help me
Adding the following annotation to your test class #TransactionConfiguration(defaultRollback = true) should fix your issue.
You mention that the AccountDAO is annotated with the #Repository annotation. Have you also annotated the DAO with #Transactional? Without it, no transaction will be created when the addSmokeEvent() method is executed in the test. Consequently, the event will be added to your DAO, but the transaction manager cannot rollback the operation.

springmvc using excel template to export

The code works well but when I setUrl to use my template in Excel, I get this error:
ApplicationObjectSupport instance [key.kotori.sms.utils.reports.StockReportsExcel: unnamed] does not run in an ApplicationContext'.
public class StockReportsExcel extends AbstractExcelView {
private StockReports reports;
public StockReportsExcel(StockReports reports) {
this.reports = reports;
//super.setUrl("report/stock.xls");
}
#Override
protected void buildExcelDocument(
Map<String, Object> model,
HSSFWorkbook workbook,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
workbook.createSheet().createRow(0).createCell(0).setCellValue("kotori");
RequestEncoding.encoding(request, response, "test.xls");
response.setContentType("application/vnd.ms-excel");
}
}
Controller
#RequestMapping("/excel.do")
public View excel(Params params) {
StockReports reports = this.stockReportService.reports(params);
StockReportsExcel excel = new StockReportsExcel(reports);
return excel;
}
I didn't set any ViewResolver in applicationContext.xml. Is there anything I'm missing in appicationContext.xml?
Here is the applicationContext.xml file.
<context:component-scan base-package="key.kotori.sms"></context:component-scan>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/sms"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingDirectoryLocations">
<list>
<value>classpath:key/kotori/sms/entity</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=true
</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:advice id="txAdivce" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get" read-only="true" />
<tx:method name="list*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdivce" pointcut="execution(* key.kotori.sms.service.*.*(..))" />
</aop:config>

Resources