Announcement Announcement Module
Collapse
No announcement yet.
Problem running a transactional test concurrently Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem running a transactional test concurrently

    I have a service class, the service class is annotated with @Transactional(propagation = Propagation.REQUIRES_NEW) and its public method is defined in an interface:

    Code:
    public interface UniqueKeyGeneratorService {
        void initializeUniqueKeys(Entity entity);
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public final class KeyGeneratorServiceImpl implements UniqueKeyGeneratorService, DisposableBean {
    
        private final UniqueKeyGeneratorStrategy strategy;
    
        private KeyGeneratorServiceImpl(final UniqueKeyGeneratorStrategy strategy) {
            this.strategy = strategy;
        }
    
        @Override
        public void initializeUniqueKeys(final Entity entity) {
            // ... the business logic
        }
    
        // ... some private methods
    
        @Override
        public void destroy() {
            strategy.destroy();
        }
    }
    And the bean is created using a FactoryBean (to initialize the strategy).

    I want to test the service, so I configured an embedded H2 database, defined a connection pool using Apache Commons DBCP and write proper test code as:

    Code:
    @ContextConfiguration("/path/to/xml/config/file.xml")
    @Transactional
    public class TestUniqueKeyGeneratorService extends AbstractTransactionalTestNGSpringContextTests {
    
        @Autowired
        private UniqueKeyGeneratorService service;
    
        @Test
        @Rollback(false)
        public void testCodeGeneration() {
            final Department department1 = new Department();
            department1.setName("Abcd");
            service.initializeUniqueKeys(department1);
            final String code = department1.getCode();
    
            Assert.assertNotNull(code);
        }
    
        // ... some more test methods
    }
    and have

    Code:
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                               http://www.springframework.org/schema/context
                               http://www.springframework.org/schema/context/spring-context-3.0.xsd
                               http://www.springframework.org/schema/tx
                               http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:db1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
      </bean>
    
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
      </bean>
    
      <tx:annotation-driven/>
    
      <bean id="uniqueKeyGeneratorService"
            class="com.mycompany.uniquekey.UniqueKeyGeneratorServiceFactoryBean">
        <property name="dataSource" ref="dataSource"/>
      </bean>
    
    </beans>
    the test passes, but when I change the @Test annotation to @Test(invocationCount = 10, singleThreaded = false, threadPoolSize = 2) (well you must have noticed that I am using TestNG), following exception occures:

    Code:
    org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Connection is closed.
    	at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:240) ~[org.springframework.jdbc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371) ~[org.springframework.transaction-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.startTransaction(TransactionalTestExecutionListener.java:514) ~[org.springframework.test-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:272) ~[org.springframework.test-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:165) ~[org.springframework.test-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:358) ~[org.springframework.test-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextBeforeTestMethod(AbstractTestNGSpringContextTests.java:146) [org.springframework.test-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_31]
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_31]
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_31]
    	at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_31]
    	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.Invoker.invokeMethod(Invoker.java:653) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111) [org.testng-6.8.jar:6.8-201210030754]
    	at org.testng.internal.thread.ThreadUtil$2.call(ThreadUtil.java:64) [org.testng-6.8.jar:6.8-201210030754]
    	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_31]
    	at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_31]
    	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_31]
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_31]
    	at java.lang.Thread.run(Thread.java:662) [na:1.6.0_31]
    Caused by: java.sql.SQLException: Connection is closed.
    	at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185) ~[org.apache.commons-dbcp-1.4.jar:1.4]
    	at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.getAutoCommit(PoolingDataSource.java:234) ~[org.apache.commons-dbcp-1.4.jar:1.4]
    	at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:218) ~[org.springframework.jdbc-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    	... 24 common frames omitted
    any idea how to handle this exception?

    p.s. I reviewed H2 documentations, and it supports multiple connections in embedded mode.
Working...
X