I am having trouble setting up a JUnit test that will rollback. I've read a few of these posts here on SO before deciding to write a question, as none seems to be the answer to my problem.
The second test case is failing because data is inserted and persisted in DB from the first test case.
Here's the JUnit test:
package com.company.group.spring.dao;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
import com.company.group.spring.model.BusObj;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:NAME_OF_CONFIG_FILE.xml"})
#Transactional
#TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
#TestExecutionListeners({TransactionalTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
public class PerPartsWCDAOTest {
#Autowired
#Qualifier("myBusObjDAO")
private BusObjDAO busObj_dao;
#Transactional
#Test
public void testInsertRollback() {
try {
BusObj busObj = new BusObj("some data...");
assertNotNull(busObj_dao);
assertNotNull(busObj);
busObj_dao.insert(perPartWC);
}
catch (NullPointerException e) {
e.printStackTrace();
}
}
#Transactional
#Rollback(false)
#Test
public void testInsert() {
BusObj busObj2 = new BusObj("some data...");
busObj_dao.insert(perPartWC2);
}
}
Here's the DAOImpl class (the class I'm trying to test):
package com.company.group.spring.dao;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.company.group.spring.model.BusObj;
#Repository("myBusObjDAO")
public class myBusObjDAOImpl implements myBusObjDAO {
private NamedParameterJdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
#Override
public void insert(BusObj someObj) {
String sql = "insert into TABLE (args...) " +
"VALUES (:named_params....)";
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(someObj);
jdbcTemplate.update(sql, paramSource);
}
}
Part of the relevant config:
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#SERVER:PORT:DB"/>
<property name="username" value="USER"/>
<property name="password" value="XXXXXX"/>
</bean>
Edit: +debug print
2012-12-18 08:50:42,177 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2012-12-18 08:50:42,342 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2012-12-18 08:50:42,344 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-18 08:50:42,361 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler#128647a[valid=true]]
2012-12-18 08:50:42,390 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update
2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into TABLE (args...) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]
2012-12-18 08:50:42,391 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Fetching JDBC Connection from DataSource
2012-12-18 08:50:42,657 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection()] Registering transaction synchronization for JDBC Connection
2012-12-18 08:50:42,671 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows
2012-12-18 08:50:42,678 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection()] Returning JDBC Connection to DataSource
2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback
2012-12-18 08:50:42,688 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-18 08:50:42,693 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
Update:
I noticed in the log, it is trying to rollback a Hibernate transaction (but this is JDBC). Then noticed the class for "txManager" is currently org.springframework.orm.hibernate4.HibernateTransactionManager, so I experimented with org.springframework.jdbc.datasource.DataSourceTransactionManager and voila, rollback worked. So I think my problem is more specifically how I'm configuring to use Hibernate and JDBC... I still don't know what is wrong.
Your JUnit and DAO classes looks fine.
The problem might be that the connection is auto-committing before the transaction is rolled back. Can you change the dataSource bean to include a defaultAutoCommit property
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#SERVER:PORT:DB"/>
<property name="username" value="USER"/>
<property name="password" value="XXXXXX"/>
<property name="defaultAutoCommit" value="false" />
</bean>
If this is not working can you paste your console logs.
The solution to my problem was specifying the dataSource for the HibernateTransactionManager. Here's the documentation on HibernateTransactionManager.
So I guess it was a mistake not posting how I defined the txManager in the original post.
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
Changed to:
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
<property name="dataSource" ref="dataSource" />
</bean>
I also added <property name="dataSource"><ref local="dataSource"/></property> to the SessionFactory definition, but it doesn't seem necessary if I'm only worried about JdbcTemplate. Suspect it's needed though if HQL is intermixed in there.
Here's what the debug print looks like when it is working. The only difference I saw was this line Returning JDBC Connection to DataSource was absent before initiate rollback
2012-12-19 08:14:29,455 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction()] Creating new transaction with name [com.company.group.spring.service.MyClassService.create]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2012-12-19 08:14:29,512 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2012-12-19 08:14:29,514 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-19 08:14:29,539 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin()] Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler#1289e48[valid=true]]
2012-12-19 08:14:29,558 [main] DEBUG [com.company.group.spring.dao.MyClassDAOImpl.insert()] Session Factory is: org.hibernate.internal.SessionFactoryImpl#1285252
2012-12-19 08:14:29,569 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.update()] Executing prepared SQL update
2012-12-19 08:14:29,570 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate.execute()] Executing prepared SQL statement [insert into MY_CLASS (COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8, COL9) VALUES (?, ?, SYSDATE,?, ?, SYSDATE, ?,?, ?)]
2012-12-19 08:14:29,608 [main] DEBUG [org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement()] SQL update affected 1 rows
2012-12-19 08:14:29,611 [main] DEBUG [org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback()] Initiating transaction rollback
2012-12-19 08:14:29,612 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback()] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2012-12-19 08:14:29,680 [main] DEBUG [org.springframework.orm.hibernate4.HibernateTransactionManager.doCleanupAfterCompletion()] Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
Related
All API call are taking long time to respond because, spring is taking long time to return cached instance of singleton bean - transactionManager. Please see log, this behaviour is consistent for each request.
2
014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/emsp/locations]
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Looking up handler method for path /locations
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Did not find handler method for [/locations]
2014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - Last-Modified value for [/emsp/locations] is: -1
2014-09-24 08:09:02,240 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'integrationEvaluationContext'
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Creating new transaction with name [com.***.emsp.service.impl.EndpointLookupServiceImpl.getEndpointLocations]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtaining JDBC connection
2014-09-24 08:09:07,407 DEBUG resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool#7cfea9ab [managed: 1, unused: 0, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection#6a4d7764)
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtained JDBC connection
2014-09-24 08:09:07,407 DEBUG spi.AbstractTransactionImpl - begin
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - initial autocommit status: true
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - disabling autocommit
2014-09-24 08:09:07,408 DEBUG hibernate4.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection#3c0b2e6e]
2014-09-24 08:09:07,408 INFO impl.EndpointLookupServiceImpl - EndpointLookupServiceImpl::getEndpointLocations - called (Custom log - after this is almost instantaneous)
If you see these two lines specifically in the above line - there is a 5sec delay - this keeps increasing after a while but comes down once tomcat is restarted.
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
My spring config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.****.emsp" />
<!-- Transaction Manager Declaration -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/emsp" />
<property name="user" value="***" />
<property name="password" value="***" />
<!-- C3P0 properties -->
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="300" />
<property name="idleConnectionTestPeriod" value="3000" />
<!--property name="testConnectionOnCheckout" value="true" /> <property
name="preferredTestQuery" value="select 1;" / -->
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.****.emsp.entity" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
</beans>
And i'm using #Transactional annotation for my service APIs involving DB transaction.
Please suggest how to go about debugging this. Also let me know if any another info is required.
Request Handling code:
#Service
public class EndpointLookupServiceImpl implements EndpointLookupService {
private static final Logger logger = Logger
.getLogger(EndpointLookupServiceImpl.class);
#Autowired
EndpointLocationDaoImpl endpointLoctionDao;
#Autowired
SsidDaoImpl ssidDao;
#Override
#Transactional
public EndpointLocationsResp getEndpointLocations(
String xJwtAssertionHeader, Map<String, List<String>> reqParams) {
logger.info("EndpointLookupServiceImpl::getEndpointLocations - called with xJwtAssertionHeader:"
+ xJwtAssertionHeader + " reqParams:" + reqParams);
.....
}
}
Using spring integration as controller for invoking the service:
<int-http:inbound-gateway id="endpointLocById"
request-channel="endpointLocByIdIn"
supported-methods="GET"
path="/locations/{locationId}"
mapped-request-headers="*"
payload-expression="#pathVariables.locationId" >
</int-http:inbound-gateway>
<int:channel id="endpointLocByIdIn"/>
<int:service-activator input-channel="endpointLocByIdIn" expression="#endpointLookupService.getEndpointLocationByLocationId(headers['x-jwt-assertion'], payload)" output-channel="out" />
Take thread dumps just before and after you see the blocking to see what your main thread is doing, Spring loads beans in a single thread, so you should be able to see where it is stuck and debug that even more.
I'm trying to unit test some persistence code and I run into the problem that the database hangs on to the rows creating in previous tests. I am also using Hibernate Search although this is not reflected in the code I'm sharing here.
I'm using Spring 3.1.x, Hibernate 4.x and HSQLDB 2.3.2
Log
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.UserRole#1]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
***First test****
DEBUG - AbstractPlatformTransactionManager.processRollback(843) | Initiating transaction rollback
DEBUG - HibernateTransactionManager.doRollback(496) | Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.User#1],EntityKey[nl.project.model.user.UserRole#1],EntityKey[nl.project.model.user.UserRole#2], EntityKey[nl.project.model.user.UserRole#3]],collectionKeys=[CollectionKey[nl.project.model.user.User.roles#1]]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
DEBUG - HibernateTransactionManager.doBegin(342) | Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - HibernateTransactionManager.doBegin(352) | Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
DEBUG - HibernateTransactionManager.doBegin(413) | Exposing Hibernate transaction as JDBC transaction [com.jolbox.bonecp.ConnectionHandle#73d17d67]
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: select this_.userRoleId as userRole1_92_0_, this_.label as label2_92_0_ from UserRole this_
DEBUG - HibernateTransactionManager.doGetTransaction(290) | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[nl.project.model.user.UserRole#3], EntityKey[nl.project.model.user.UserRole#2], EntityKey[nl.project.model.user.UserRole#1]],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
DEBUG - AbstractPlatformTransactionManager.handleExistingTransaction(470) | Participating in existing transaction
Hibernate: insert into UserRole (userRoleId, label) values (default, ?)
WARN - SqlExceptionHelper.logExceptions(144) | SQL Error: -104, SQLState: 23505
ERROR - SqlExceptionHelper.logExceptions(146) | integrity constraint violation: unique constraint or index violation; UK_O0VIK8LBO8UYMR8WUDN5T21QX table: USERROLE
Code
#Entity
#Immutable
#Table
#NaturalIdCache(region=CacheRegion.NATURAL)
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,region=CacheRegion.USER)
public class UserRole implements Serializable{
public static final String ROLE_ANONYMOUS="ROLE_ANONYMOUS";
public static final String ROLE_USER="ROLE_USER";
public static final String ROLE_PROVENDOR="ROLE_PROVENDOR";
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable=false, updatable=false)
private Long id;
#Column(nullable=false,unique=true,updatable=false)
#NaturalId
private String label;
...
}
Code
public class CoreTest extends TestCase {
#Inject
protected SimpleManager<Long> simpleMgr;
public void baseSetup(){
simpleMgr.flush();
simpleMgr.clear();
//after 1st test this contains all created UserRoles
List roles = simpleMgr.getAll(UserRole.class);
UserRole role = new UserRole(UserRole.ROLE_ANONYMOUS);
simpleMgr.save(role);
role = new UserRole(UserRole.ROLE_USER);
simpleMgr.save(role);
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {
"classpath:/spring/applicationContext.xml"
"classpath:/spring/applicationContext-transaction.xml"})
public class MyManagerTest extends CoreTest{
#Before
public void methodSetup(){
super.baseSetup();
role = new UserRole(UserRole.ROLE_PROUSER);
simpleMgr.save(role);
simpleMgr.save(userMgr.createUser("marc", "marc#gmail.com"));
simpleMgr.flush();
}
#Test
#Transactional
public void test1(){
...
}
#Test
#Transactional
public void test2(){
....
}
Transaction management
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="mainDataSource"/>
</bean>
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
[...]
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.connection.driver_class=${jdbc.driverClassName}
hibernate.jdbc.batch_size=30
hibernate.dialect=${hibernate.dialect}
hibernate.connection.autoReconnect=true
hibernate.connection.autoReconnectForPools=true
hibernate.connection.autocommit=false
</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Try adding #Transactional annotation on test class. http://docs.spring.io/spring/docs/2.0.x/api/org/springframework/transaction/annotation/Transactional.html
Try adding transaction interceptor:
<beans xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Extend AbstractTransactionalJunit4SpringContextTests or add #TestExecutionListeners(TransactionalTestExecutionListener.class).
So, I finally got this working by specifying defaultAutoCommit=false on the BoneCPDatasource. AFAIK this is way too low level for this configuration, and therefore possibly wrong. But at least it's working.
I have a Java EE Application with Spring 3.1.1 and Hibernate 4.1. Now I wanted to speed up things and saw that the bottleneck is the opening + closing of multiple transactions in one request.
Now I removed all #Transactional annotations and created my own OpenSessionInViewFilter, which opens and closes one transaction.
package utils.spring;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class CustomHibernateSessionViewFilter extends OpenSessionInViewFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
} else {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
//BEGIN TRANSACTION
session.beginTransaction();
}
try {
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
// COMMIT
sessionHolder.getSession().getTransaction().commit();
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
}
}
Is that a good idea? It seems to work and speeded up things.
Here is my log for the transactions:
http-bio-8080-exec-3 01/03/2013 11:25:20,947 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doGetTransaction | Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
http-bio-8080-exec-3 01/03/2013 11:25:20,948 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | getTransaction | Creating new transaction with name [by2.server.service.UserService.loadUserByUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
http-bio-8080-exec-3 01/03/2013 11:25:20,948 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doBegin | Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
http-bio-8080-exec-3 01/03/2013 11:25:21,172 | DEBUG | org.springframework.orm.hibernate4.HibernateTransactionManager | doBegin | Exposing Hibernate transaction as JDBC transaction [org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler#1e7b64f4[valid=true]]
http-bio-8080-exec-3 01/03/2013 11:25:21,188 | DEBUG | org.hibernate.SQL | logStatement | select userentity_.userID as userID5_ from users userentity_ where userentity_.username=?
connection pool
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.1.1.Final</version>
</dependency>
<property name="hibernateProperties">
<value>
hibernate.hbm2ddl.auto=update
hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.bytecode.use_reflection_optimizer=false
hibernate.max_fetch_depth=0
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=300
hibernate.c3p0.max_statements=50
hibernate.c3p0.idle_test_period=3000
</value>
</property>
but the open session in view filter seems to close the sessions
finally {
if (!participate) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
But even when I remove the filter, Hibernate doesn't seem to use the pool.
I would say no.
For example, you'll save some product or whatever in the database, and show a success page or redirect, thinking everything has been saved. But the transaction won't be committed yet and could still rollback after you have displayed the success message.
And with Hibernate, the probability of this happening is even bigger, because nothing will be written to the database until flush time, which will happen just before the commit.
Moreover the transaction will live longer than necessary, preventing other transactions to procees in case it has put a lock on rows or tables in the database, resulting in poorer performance and scalability.
What's wrong with the default Spring OpenSessionInViewFilter, which lets the session open, but still uses service-level, short transactions? Why do your requests open multiple transactions? My quess is that you're doing too many calls from the UI layer to the service layer in a single request.
Finally i configured my pool the right way... the solution was not to add some c3p0 properties to my hibernate config, i just had to replace my datasource-bean
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- Connection properties -->
<property name="driverClass" value="org.postgresql.Driver" />
<property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/DBNAME" />
<property name="user" value="xxx" />
<property name="password" value="xxx" />
<!-- Pool properties -->
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxStatements" value="50" />
<property name="idleConnectionTestPeriod" value="3000" />
<property name="loginTimeout" value="300" />
</bean>
runs like a charm now
I am starting a project using Spring 3.2.1.RELEASE, Hibernate 4.1.9.FINAL as jpa provider, spring data 1.2.0.RELEASE for repository and bitronix 2.1.3 as transaction manager. I am new to all of these technologies so I'm sorry if I'm missing some huge point.
I am running a simple unit test to create a User object in a database:
#ContextConfiguration(locations={"classpath:tests-context.xml"})
#Transactional
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#RunWith(SpringJUnit4ClassRunner.class)
public class UserTest extends AbstractTransactionalJUnit4SpringContextTests
{
#Autowired
protected UserMgmtService userService;
#Test
public void createUserTest()
{
User user = new User();
user.setFirstName("jonny");
user.setLastName("doe");
user.setUsername("user5");
user.setPasswordHash("1238");
user.setEmail("user5#domain.com");
System.out.println("Created user" + user);
User testUser = userService.saveUser(user);
System.out.println("Saved user" + testUser);
Assert.assertEquals("The user should be equal to saved user", user, testUser);
}
}
My test-context.xml used is as follows:
<context:annotation-config/>
<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
</bean>
<!-- DataSource definition -->
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource" />
<property name="uniqueName" value="jdbc/MySQL_Test_Repository" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="5" />
<property name="allowLocalTransactions" value="true" />
<property name="driverProperties">
<props>
<prop key="driverClassName">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306 MySQL_Test_Repository</prop>
<prop key="user">root</prop>
<prop key="password">123654</prop>
</props>
</property>
</bean>
<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="BitronixTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<!-- AOP configuration for transactions -->
<aop:config>
<aop:pointcut id="userServiceMethods"
expression="execution(* users.service.UserMgmtService.*(..))" />
<aop:advisor advice-ref="transactionAdvice"
pointcut-ref="userServiceMethods" />
</aop:config>
<!-- Transaction configuration -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- bean declaring the property map for the entity manager factory bean -->
<bean id="jpaPropertyMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!-- show the sql code executed -->
<entry key="hibernate.show_sql" value="true"/>
<!-- format the shown sql code -->
<entry key="hibernate.format_sql" value="true"/>
<!-- enables hibernate to create db schemas from classes;
Possible values: validate | update | create | create-drop
with create-drop the schema will be created/dropped for each hibernate sesssion open/close-->
<entry key="hibernate.hbm2ddl.auto" value="update"/>
<!-- sets the hibernate classname for the TransactionManagerLookup;
hibernate wraps and hides the underlying transaction system and needs a reference
to the transaction manager used -->
<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<entry key="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.BTMTransactionManagerLookup"/>
</map>
</property>
</bean>
<!-- bean declaring the entity manager factory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ruleEditor.persistence"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaPropertyMap" ref="jpaPropertyMap"/>
</bean>
<!-- The location where Spring scans for interfaces implementing the JPARepository
and creates their implementation -->
<jpa:repositories base-package="users.repository" />
<!-- Persistence annotations for post processing -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- User service implementation bean -->
<bean id="userMgmtService" class="users.service.impl.UserMgmtServiceImpl"/>
</beans>
The Repository implementation is a standard JPARepository:
public interface UserRepository extends JpaRepository<User, Long>
{
User findByUsername(String username);
}
And the service implementation only makes calls to the repository:
#Service("userMgmtService")
public class UserMgmtServiceImpl implements UserMgmtService
{
#Autowired
private UserRepository userRepository;
#Override
public User saveUser(User user)
{
User savedUser = userRepository.save(user);
return savedUser;
}
The problem is that when I execute the test, it passes, but no user is created in the database. I thought it might be because of the Rollback behavior so I set the defaultRollback=false in the User test. Here is some information provided by the transaction framework when set to DEBUG that might be relevant:
Running UserTest
2013-02-12 13:01:12 INFO XmlBeanDefinitionReader:315 - Loading XML bean definitionsfrom class path resource [tests-context.xml]
2013-02-12 13:01:12 INFO GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext#7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'dataSource' of type [class bitronix.tm.resource.jdbc.PoolingDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class org.springframework.beans.factory.config.MapFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class java.util.LinkedHashMap] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'ruleEditor.persistence'
2013-02-12 13:01:13 INFO SchemaUpdate:182 - HHH000228: Running hbm2ddl schema update
2013-02-12 13:01:13 INFO SchemaUpdate:193 - HHH000102: Fetching database metadata
2013-02-12 13:01:13 INFO SchemaUpdate:205 - HHH000396: Updating schema
2013-02-12 13:01:13 INFO TableMetadata:65 - HHH000261: Table found: MySQL_Test_Repository.user
2013-02-12 13:01:13 INFO TableMetadata:66 - HHH000037: Columns: [id, enabled, first_name, username, email, password_hash, last_name]
2013-02-12 13:01:13 INFO TableMetadata:68 - HHH000108: Foreign keys: []
2013-02-12 13:01:13 INFO TableMetadata:69 - HHH000126: Indexes: [id, username, primary]
2013-02-12 13:01:13 INFO SchemaUpdate:240 - HHH000232: Schema update complete
2013-02-12 13:01:13 INFO BitronixTransactionManager:390 - Bitronix Transaction Manager version 2.1.3
2013-02-12 13:01:13 WARN Configuration:649 - cannot get this JVM unique ID. Make sure it is configured and you only use ASCII characters. Will use IP address instead (unsafe for production usage!).
2013-02-12 13:01:13 INFO Recoverer:152 - recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 1 resource(s) [jdbc/MySQL_Test_Repository]
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' of type [class org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO JtaTransactionManager:470 - Using JTA UserTransaction: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 INFO JtaTransactionManager:481 - Using JTA TransactionManager: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 DEBUG NameMatchTransactionAttributeSource:94 - Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception]
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG JtaTransactionManager:365 - Creating new transaction with name [createUserTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:279 - Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager#2a3998f8]; rollback [false]
Created userusers.model.User#63aa9dc1[userId=0,first name=jonny,last name=doe,email=user5#domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
Saved userusers.model.User#6b38579e[userId=0,first name=jonny,last name=doe,email=user5#domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:752 - Initiating transaction commit
2013-02-12 13:01:14 WARN Preparer:69 - executing transaction with 0 enlisted resource
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:299 - Committed transaction after test execution for test context [TestContext#5a93c236 testClass = UserTest, testInstance = UserTest#1ab395af, testMethod = createUserTest#UserTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#42821db testClass = UserTest, locations = '{classpath:tests-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.029 sec
2013-02-12 13:01:14 INFO GenericApplicationContext:1042 - Closing org.springframework.context.support.GenericApplicationContext#7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:14 INFO BitronixTransactionManager:320 - shutting down Bitronix Transaction Manager
2013-02-12 13:01:14 INFO LocalContainerEntityManagerFactoryBean:441 - Closing JPA EntityManagerFactory for persistence unit 'ruleEditor.persistence'
The logs show a testException=[null] but I have no idea why that would be.. I even tried to use the saveAndFlush() method provided by the JPARepository but doing so I get the error javax.persistence.TransactionRequiredException: no transaction is in progress
So if anyone has some idea of what I am doing wrong and can point me in the right direction I would very much appreciate the help.
After some careful reading of the logs, I found this warning:
WARN Ejb3Configuration:1309 - HHH000193: Overriding hibernate.transaction.factory_class is dangerous, this might break the EJB3 specification implementation
This was related to a property that I had set in the jpaPropertyMap bean in my tests-context.xml file:
<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
It turns out that once I removed this line in the configuration file I could see hibernate performing an "insert" action and the user was actually created in the database. Since I am new to spring and all the technologies I used, I must have copied the configuration from somewhere without really analysing it. So, I am now able to run junit4 tests in a project using spring data, hibernate and bitronix as transaction manager.
We want to use the Atomikos JTA Transaction Manager. We have a unit test which we want to roll back once it completes, thereby leaving the table clean for the next run.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/appContext-test.xml"})
#TransactionConfiguration(transactionManager = "txManager")
public class InboundEmailDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private InboundEmailDao dao;
#BeforeTransaction
public void beforeTransaction() {
System.out.println("InboundEmailDaoTest: Rows before: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#AfterTransaction
public void afterTransaction() {
System.out.println("InboundEmailDaoTest: Rows after: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#Test
public void when_inserting_then_record_is_created() {
String subject = "subject here";
InboundEmail inboundEmail = new InboundEmail();
inboundEmail.setEmailSubject(subject);
//More here...
inboundEmail.setOriginator("originator");
inboundEmail.setOriginSystem("myapp");
inboundEmail.setProcessingStatus("RECEIVED");
inboundEmail.setAttachment("big fat attachment here");
inboundEmail.setAttachmentFilename("Big fat attachment filename here");
int rowsBefore = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows before: " + rowsBefore);
dao.insert(inboundEmail);
int rowsAfter = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows after: " + rowsAfter);
assertTrue((rowsAfter == rowsBefore + 1));
}
}
When we run with the Spring-bundled JTA transaction manager configged as below
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:02:22.751 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:02:22.798 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
InboundEmailDaoTest: Rows before: 0
12:02:23.770 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager#8e4805]; rollback [true]
Rows before: 0
12:02:23.832 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#44d990]
12:02:23.835 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:02:23.888 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
Rows after: 1
12:02:23.927 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Rolled back transaction after test execution for test context [[TestContext#1958cc2 testClass = InboundEmailDaoTest, testInstance = co.myco.myapp.repository.dao.InboundEmailDaoTest#14c28db, testMethod = when_inserting_then_record_is_created#InboundEmailDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#10e687b testClass = InboundEmailDaoTest, locations = '{classpath:spring/appContext-test.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
InboundEmailDaoTest: Rows after: 0
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.252 sec
But when we run with the Atomikos Transaction Manager configged as follows:
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<!-- ATOMIKOS Transaction-Manager-Specific Setup -->
<bean id="AtomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<!-- when close is called, should we force
transactions to terminate or not? -->
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:12:42.267 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,AtomikosTransactionManager,AtomikosUserTransaction,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:12:42.310 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
12:12:42.853 INFO [main][com.atomikos.logging.LoggerFactory] Using Slf4J for logging.
12:12:42.854 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] No properties path set - looking for transactions.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] transactions.properties not found - looking for jta.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] Failed to open transactions properties file - using default values
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Starting read of logfile C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Done read of logfile
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Logfile closed: C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING core version: 3.8.0
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_name = tm.out
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_count = 1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.automatic_resource_registration = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.client_demarcation = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.threaded_2pc = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.serial_jta_transactions = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_log_level = WARN
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_actives = 50
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.checkpoint_interval = 500
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.enable_logging = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.output_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_name = tmlog
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_limit = -1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_timeout = 300000
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.tm_unique_name = 100.100.100.100.tm
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContextFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.provider.url = rmi://localhost:1099
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.service = com.atomikos.icatch.standalone.UserTransactionServiceFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.force_shutdown_on_vm_exit = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.default_jta_timeout = 10000
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA UserTransaction: com.atomikos.icatch.jta.UserTransactionImp#1568654
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA TransactionManager: com.atomikos.icatch.jta.UserTransactionManager#18d30fb
InboundEmailDaoTest: Rows before: 1
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.165 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ACTIVE
12:12:43.170 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] TaskManager: initializing...
12:12:43.170 INFO [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using JDK thread pooling...
12:12:43.176 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using executor class com.atomikos.icatch.imp.thread.Java15ExecutorFactory$Executor
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.Java15ExecutorFactory] (1.5) executing task: com.atomikos.timing.PooledAlarmTimer#160bf50
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.ThreadFactory] ThreadFactory: creating new thread: Atomikos:0
12:12:43.178 DEBUG [main][com.atomikos.icatch.imp.TransactionServiceImp] Creating composite transaction: 100.100.100.100.tm0000100049
12:12:43.182 INFO [main][com.atomikos.icatch.imp.BaseTransactionManager] createCompositeTransaction ( 300000 ): created new ROOT transaction with id 100.100.100.100.tm0000100049
12:12:43.185 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager#ed9f47]; rollback [true]
Rows before: 1
12:12:43.376 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#96ad7c]
12:12:43.379 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:12:43.429 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
12:12:43.494 INFO [main][org.springframework.beans.factory.xml.XmlBeanDefinitionReader] Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
12:12:43.529 INFO [main][org.springframework.jdbc.support.SQLErrorCodesFactory] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.533 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ABORTING
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: TERMINATED
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : stopping timer...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposing statehandler TERMINATED...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposed.
12:12:43.536 DEBUG [main][com.atomikos.icatch.imp.CompositeTransactionImp] Ignoring error during event callback
java.lang.IllegalStateException: Transaction no longer active
at com.atomikos.icatch.imp.TxTerminatedStateHandler.rollbackWithStateCheck(TxTerminatedStateHandler.java:106)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.imp.CompositeTransactionImp.entered(CompositeTransactionImp.java:373)
at com.atomikos.finitestates.FSMImp.notifyListeners(FSMImp.java:186)
at com.atomikos.finitestates.FSMImp.setState(FSMImp.java:277)
at com.atomikos.icatch.imp.CoordinatorImp.setState(CoordinatorImp.java:429)
at com.atomikos.icatch.imp.CoordinatorImp.setStateHandler(CoordinatorImp.java:286)
at com.atomikos.icatch.imp.CoordinatorStateHandler.rollback(CoordinatorStateHandler.java:764)
at com.atomikos.icatch.imp.ActiveStateHandler.rollback(ActiveStateHandler.java:264)
at com.atomikos.icatch.imp.CoordinatorImp.rollback(CoordinatorImp.java:747)
at com.atomikos.icatch.imp.TransactionStateHandler.rollback(TransactionStateHandler.java:179)
at com.atomikos.icatch.imp.TransactionStateHandler.rollbackWithStateCheck(TransactionStateHandler.java:197)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.jta.TransactionImp.rollback(TransactionImp.java:234)
at com.atomikos.icatch.jta.TransactionManagerImp.rollback(TransactionManagerImp.java:524)
at com.atomikos.icatch.jta.UserTransactionImp.rollback(UserTransactionImp.java:141)
at org.springframework.transaction.jta.JtaTransactionManager.doRollback(JtaTransactionManager.java:1037)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:518)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:292)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:185)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)
12:12:43.537 INFO [main][com.atomikos.icatch.imp.CompositeTransactionImp] rollback() done of transaction 100.100.100.100.tm0000100049
In short, it seems Atomikos is ABORTING and TERMINATING our Tx mid flight for no apparent reason. Does anyone have any idea why?
The problem can be in a configuration that is not present in your code snippets.
Datasource should be wrapped into com.atomikos.jdbc.AtomikosDataSourceBean.
If you use Hibernate in your DAO implementation, there are properties that should be set up, like hibernate.transaction.factory_class or hibernate.transaction.manager_lookup_class.
I have a similar set-up and this works for me.
#TransactionConfiguration(transactionManager = "txManager", defaultrollback=true)
You can also set individual #Test methods with #Rollback(true/false)
Depending on what you are calling in your tests you may have to set #Transactional on the class or
#Transactional(propagation=Propagation.REQUIRES_NEW) per transaction #Test method