Transaction rollback in SSM framework problem - spring

software version :jdk 8 spring 4.0 mybatis-3.2.7.jar mybatis-spring-1.2.2.jar ojdbc6.jar oracle 11g
applicationContext.xml:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
id="dataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="appTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="appTransactionManager" />
junit code:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "appTransactionManager", defaultRollback = true)
#Transactional(rollbackFor = Exception.class)
#ContextConfiguration("classpath:applicationContext.xml")
public class GenerateJylshTest {
#Test
#Rollback(true)
public void generateJylshTest() {
String jyjgbh = "4201000000";
GenerateJylsh generator = new GenerateJylsh();
int i;
for(i = 0;i < 3;i++) {
String jylshString = generator.generateJylsh(jyjgbh);
System.out.println(jylshString);
}
int k = 1/0;
}
}
console result:
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
JDBC Connection [oracle.jdbc.driver.T4CConnection#172b013] will be managed by Spring
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800027
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800028(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800028
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800028
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800029(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800029
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800029
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800030(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800030
Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
2019-11-08 16:31:09 [main] - [ INFO ] Rolled back transaction after test execution for test context [DefaultTestContext#f316aeb testClass = GenerateJylshTest, testInstance = test.GenerateJylshTest#6aa3a905, testMethod = generateJylshTest#GenerateJylshTest, testException = java.lang.RuntimeException, mergedContextConfiguration = [MergedContextConfiguration#a22cb6a testClass = GenerateJylshTest, locations = '{classpath:applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
2019-11-08 16:31:09 [Thread-1] - [ INFO ] Closing org.springframework.context.support.GenericApplicationContext#4667ae56: startup date [Fri Nov 08 16:31:05 CST 2019]; root of context hierarchy
I used to think that this result code
Transaction synchronization rolling back SqlSession
Transaction synchronization closing SqlSession
means the transaction rollback is already done,but the fact is data still update to the oracle database.
So,I want to konw why.Thanks for any help.

Related

Transaction configure failed in Spring Boot

update:
I found that I inject class A into class C which extends an external class,
and that class didn't managed by spring, like this:
public class C extends ExternalClass {
#AutoWired
private A a;
//doSomething...
}
That should be the main cause of transaction failure.
Another question: is there any way to make spring manage transaction of class A which has injected into anothor class that isn't handled by spring?
I'm building a project with Spring Boot and Mybatis.
I have a problem that one of service class cannot a create transactional connection and won't perform a roll back.
I found that if I removed injection of A Class in B Class, like this:
class A{
//#Autowired
//private B b;
// b is not used in this class
#Autowired
private ADao dao;
}
class B{
#Autowired
private BDao dao;
//Transaction of this method failed
//session didn't roll back
public void (){
dao.insert(new Entity ());
//Exception here
}
}
The connection created by class B would be transactional. Both of two class are in the same package, but if I add that injection, the transaction would fail. What made me much confused is that class B can inject into other class, and transaction would work well too.
Here is the log:
2018-01-05 21:30:33.861 DEBUG 10346 --- [http-nio-8099-exec-2] org.mybatis.spring.SqlSessionUtils 97 : Creating a new SqlSession
2018-01-05 21:30:33.866 DEBUG 10346 --- [http-nio-8099-exec-2] org.mybatis.spring.SqlSessionUtils 148 : SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#3aeb5ca8] was not registered for synchronization because synchronization is not active
2018-01-05 21:30:33.888 DEBUG 10346 --- [http-nio-8099-exec-2] o.s.jdbc.datasource.DataSourceUtils 110 : Fetching JDBC Connection from DataSource
2018-01-05 21:30:33.888 DEBUG 10346 --- [http-nio-8099-exec-2] o.s.j.d.DriverManagerDataSource 142 : Creating new JDBC DriverManager Connection to [jdbc:mariadb://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true]
2018-01-05 21:30:33.905 DEBUG 10346 --- [http-nio-8099-exec-2] o.m.s.t.SpringManagedTransaction 87 : JDBC Connection [org.mariadb.jdbc.MySQLConnection#2bad8689] will not be managed by Spring
2018-01-05 21:30:33.908 DEBUG 10346 --- [http-nio-8099-exec-2] p.c.z.admin.dao.UserDao.insertSelective 159 : ==> Preparing: INSERT INTO sys_user ( id,username ) VALUES( ?,? )
2018-01-05 21:30:33.916 DEBUG 10346 --- [http-nio-8099-exec-2] p.c.z.admin.dao.UserDao.insertSelective 159 : ==> Parameters: null, test(String)
2018-01-05 21:30:33.929 DEBUG 10346 --- [http-nio-8099-exec-2] p.c.z.admin.dao.UserDao.insertSelective 159 : <== Updates: 1
2018-01-05 21:30:33.932 DEBUG 10346 --- [http-nio-8099-exec-2] p.c.z.a.d.U.insertSelective!selectKey 159 : ==> Executing: SELECT LAST_INSERT_ID()
2018-01-05 21:30:33.940 DEBUG 10346 --- [http-nio-8099-exec-2] p.c.z.a.d.U.insertSelective!selectKey 159 : <== Total: 1
2018-01-05 21:30:33.942 DEBUG 10346 --- [http-nio-8099-exec-2] org.mybatis.spring.SqlSessionUtils 191 : Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#3aeb5ca8]
I've tried 3 ways to config transaction:
with java config:
#Bean(name = "transactionInterceptor")
public TransactionInterceptor transactionInterceptor(PlatformTransactionManager platformTransactionManager) {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionManager(platformTransactionManager);
Properties transactionAttributes = new Properties();
transactionAttributes.setProperty("insert*","PROPAGATION_REQUIRED,-Throwable");
transactionAttributes.setProperty("update*","PROPAGATION_REQUIRED,-Throwable");
transactionAttributes.setProperty("delete*","PROPAGATION_REQUIRED,-Throwable");
transactionAttributes.setProperty("select*","PROPAGATION_REQUIRED,-Throwable,readOnly");
transactionInterceptor.setTransactionAttributes(transactionAttributes);
return transactionInterceptor;
}
#Bean
public BeanNameAutoProxyCreator transactionAutoProxy() {
BeanNameAutoProxyCreator transactionAutoProxy = new BeanNameAutoProxyCreator();
transactionAutoProxy.setProxyTargetClass(true);
transactionAutoProxy.setBeanNames("*ServiceImpl");
transactionAutoProxy.setInterceptorNames("transactionInterceptor");
return transactionAutoProxy;
}
and with xml:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="services"
expression="execution(* root.*.service.*.*(..))"/>
<aop:advisor pointcut-ref="services" advice-ref="txAdvice"/>
</aop:config>
and with #Transactional.
However none of them worked.
The problem is that if you inject a class into another one which is not a spring managed bean, then the spring transaction management will failed.
So while having a transaction failure, go check if there is a wrong dependency injection.

Hibernate sql query format in console

I'm trying to log the sql queries i'm calling from a .xml file. The problem i'm facing is that when i see the log, it's not well formatted. Also, i don't know why it appears repeated...
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper.
[main] INFO org.springframework.orm.hibernate5.HibernateTransactionManager - Using DataSource [org.apache.commons.dbcp2.BasicDataSource#1f03fba0] of Hibernate SessionFactory for HibernateTransactionManager
[main] INFO org.springframework.aop.framework.CglibAopProxy - Unable to proxy method [public final void com.servicios.test.TestRestauranteManager.findProveedoresByIdRestaurante() throws com.servicios.util.exceptions.AlergenosException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
[main] INFO org.springframework.test.context.transaction.TransactionContext - Began transaction (1) for test context [DefaultTestContext#436bd4df testClass = TestRestauranteManager, testInstance = com.servicios.test.TestRestauranteManager#6848a051, testMethod = findProveedoresByIdRestaurante#TestRestauranteManager, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#149b0577 testClass = TestRestauranteManager, locations = '{classpath:test-applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.hibernate5.HibernateTransactionManager#5740ff5e]; rollback [true]
select restaurant0_."ID_RESTAURANTE" as ID_RESTA1_4_0_, restaurant0_."DESCRIPCION" as DESCRIPC2_4_0_, restaurant0_."ID_CADENA_RESTAURANTE" as ID_CADEN3_4_0_ from "RESTAURANTE" restaurant0_ where restaurant0_."ID_RESTAURANTE"=?
Hibernate: select restaurant0_."ID_RESTAURANTE" as ID_RESTA1_4_0_, restaurant0_."DESCRIPCION" as DESCRIPC2_4_0_, restaurant0_."ID_CADENA_RESTAURANTE" as ID_CADEN3_4_0_ from "RESTAURANTE" restaurant0_ where restaurant0_."ID_RESTAURANTE"=?
binding parameter [1] as [BIGINT] - [0]
I would like to have something like
[main] INFO org.dozer.DozerBeanMapper - Initializing a new instance of dozer bean mapper. [main] INFO org.dozer.DozerBeanMapper -
Initializing a new instance of dozer bean mapper. [main] INFO
org.springframework.orm.hibernate5.HibernateTransactionManager - Using
DataSource [org.apache.commons.dbcp2.BasicDataSource#1f03fba0] of
Hibernate SessionFactory for HibernateTransactionManager [main] INFO
org.springframework.aop.framework.CglibAopProxy - Unable to proxy
method [public final void
com.servicios.test.TestRestauranteManager.findProveedoresByIdRestaurante()
throws com.servicios.util.exceptions.AlergenosException] because it is
final: All calls to this method via a proxy will NOT be routed to the
target instance. [main] INFO
org.springframework.test.context.transaction.TransactionContext -
Began transaction (1) for test context [DefaultTestContext#436bd4df
testClass = TestRestauranteManager, testInstance =
com.servicios.test.TestRestauranteManager#6848a051, testMethod =
findProveedoresByIdRestaurante#TestRestauranteManager, testException =
[null], mergedContextConfiguration =
[MergedContextConfiguration#149b0577 testClass =
TestRestauranteManager, locations =
'{classpath:test-applicationContext.xml}', classes = '{}',
contextInitializerClasses = '[]', activeProfiles = '{}',
propertySourceLocations = '{}', propertySourceProperties = '{}',
contextLoader =
'org.springframework.test.context.support.DelegatingSmartContextLoader',
parent = [null]]]; transaction manager
[org.springframework.orm.hibernate5.HibernateTransactionManager#5740ff5e];
Hibernate: select
p."DESCRIPCION" as "descripcion",
p."ID_PROVEEDOR" as "idProveedor"
from
"RESTAURANTE_PROVEEDOR" rp
inner join
"PROVEEDOR" p
on rp."ID_PROVEEDOR" = p."ID_PROVEEDOR"
where
rp."ID_RESTAURANTE" = ? binding parameter [1] as [BIGINT] - [0]
My log4j.properties is the following:
log4j.rootLogger=INFO, stdout
log4j.logger.org.hibernate=INFO
log4j.logger.org.hibernate.SQL=TRACE
log4j.logger.org.hibernate.type=ALL
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.rootConsola.layout.ConversionPattern=(%d{dd/MM/yyyy-HH:mm:ss}) %-5p: %-40c{1} - %m%n
And in my ApplicationContext.xml I have this
...
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="com.servicios.vo"/>
<property name="mappingLocations">
<list>
<value>classpath*:hibernate/queries/**/*.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
...
Thanks in advance!!
The hibernate.format_sql setting does not apply to Exception reasons when something happens and an Exception is thrown that includes a SQL fragment.
In other words, hibernate.format_sql only applies when Hibernate writes the SQL it's about to execute to the logs, not when it's included as part of some Exception reason.

Junit test not rolling back after transaction

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.

Transaction Repeatable Read Isolation does not work properly in PostgreSQL

I use Spring framework with DataSourceTransactionManager and I noticed that Repeatable Read Isolation does not work properly with Postgresql. According to Postgres documentation:
repeatable read transaction cannot modify or lock rows changed by
other transactions after the repeatable read transaction began.
Lets assume that we have 2 transactions: T1 and T2. Assume this scenario:
T1 begin -> T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit
Transaction T1 should be rolled back with the message
ERROR: could not serialize access due to concurrent update
but T1 is committed and overwrites T2 update.
I made simple example in Spring to demonstrate it:
Sql:
CREATE TABLE tab
(
id bigint NOT NULL,
name character varying(50),
CONSTRAINT tab_pkey PRIMARY KEY (id )
)
INSERT INTO tab(id, name) VALUES (1, 'name');
DataSource configuration:
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
id="property">
<property name="location" value="classpath:database.properties"></property>
</bean>
<bean id="service" class="com.kulig.db_test.ServiceImpl">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
</beans>
Service interface:
public interface Service {
public void dosth(String name);
public void dosth2(String name);
}
Implementation of service interface:
public class ServiceImpl extends JdbcTemplate implements Service {
public ServiceImpl(DataSource dataSource) {
super(dataSource);
}
String sqlQuery="update tab set name=? where id=?";
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void dosth(String name) {
System.out.println("Before waiting, "+Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Start, "+Thread.currentThread().getName());
update(sqlQuery, name,1);
System.out.println("Stop,"+Thread.currentThread().getName());
}
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void dosth2(String name) {
System.out.println("Before waiting, "+Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Start, "+Thread.currentThread().getName());
update(sqlQuery, name,1);
System.out.println("Stop, "+Thread.currentThread().getName());
}
}
Main:
public class MainApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("data-tx-jpa.xml");
final Service service = applicationContext.getBean(Service.class);
Runnable runnable1 = new Runnable() {
public void run() {
service.dosth("name1");
}
};
Runnable runnable2 = new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.dosth2("name2");
}
};
Thread thread1 = new Thread(runnable1, "thread1");
Thread thread2 = new Thread(runnable2, "thread2");
thread1.start();
thread2.start();
}
}
Logs:
main 2014-01-08 10:34:04,636 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#786bb78a: startup date [Wed Jan 08 10:34:04 CET 2014]; root of context hierarchy>
main 2014-01-08 10:34:04,687 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [data-tx-jpa.xml]>
main 2014-01-08 10:34:04,967 INFO [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] - <Loading properties file from class path resource [database.properties]>
main 2014-01-08 10:34:04,998 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#4d8657b9: defining beans [dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,property,service,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy>
main 2014-01-08 10:34:05,080 DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - <Adding transactional method 'dosth2' with attribute: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,108 DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - <Adding transactional method 'dosth' with attribute: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,116 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [com.kulig.db_test.ServiceImpl.dosth]: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,180 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] for JDBC transaction>
thread1 2014-01-08 10:34:05,188 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Changing isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 4>
thread1 2014-01-08 10:34:05,204 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to manual commit>
Before waiting, thread1
thread2 2014-01-08 10:34:06,106 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [com.kulig.db_test.ServiceImpl.dosth2]: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread2 2014-01-08 10:34:06,111 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] for JDBC transaction>
thread2 2014-01-08 10:34:06,111 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Changing isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 4>
thread2 2014-01-08 10:34:06,112 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to manual commit>
Before waiting, thread2
Start, thread2
thread2 2014-01-08 10:34:11,115 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL update>
thread2 2014-01-08 10:34:11,116 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL statement [update tab set name=? where id=?]>
thread2 2014-01-08 10:34:11,125 DEBUG [com.kulig.db_test.ServiceImpl] - <SQL update affected 1 rows>
Stop, thread2
thread2 2014-01-08 10:34:11,127 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
thread2 2014-01-08 10:34:11,128 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver]>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Resetting isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 2>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] after transaction>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
Start, thread1
thread1 2014-01-08 10:34:15,205 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL update>
thread1 2014-01-08 10:34:15,205 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL statement [update tab set name=? where id=?]>
thread1 2014-01-08 10:34:15,207 DEBUG [com.kulig.db_test.ServiceImpl] - <SQL update affected 1 rows>
Stop,thread1
thread1 2014-01-08 10:34:15,207 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
thread1 2014-01-08 10:34:15,207 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver]>
thread1 2014-01-08 10:34:15,233 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Resetting isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 2>
thread1 2014-01-08 10:34:15,234 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] after transaction>
thread1 2014-01-08 10:34:15,234 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
Where is bug? Do I do something wrong or Postgres transaction does not work?
EDIT
This scenerio works properly:
T1 begin -> **T1 select row** ->T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit
You are using illegal outside knowledge to say that one transaction begin before the other. The database has fulfilled its obligation as long as there exists a legal ordering of actions which would produce the same end results from the database as the actually produced results. It is not required that this legal ordering match the ordering you think you measured with your stop watch.
I used Wireshark to analyze communication of my java application and PostgreSQL. I noticed that begin of transaction take place before send first query. I thought that transaction begins before start of method with #Transactional annotation. So scenerio:
T1 begin -> T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit
is not correct.
Real scenerio which I tested is:
T2 begin -> `T2 update row` -> T2 commit -> T1 begin ->T1 update the same row -> T1 commit
To test first scenerio, some query (select version() for example) should be executed before waiting in transaction T1. This query is necessary to begin a transaction T1 before start of transaction T2. In this scenerio everything is working properly.

Spring Unit Tests won't roll back when using Atomikos JTA 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

Resources