Announcement Announcement Module
Collapse
No announcement yet.
Testing jdbctemplate with rollback Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Testing jdbctemplate with rollback

    I'm having problems testing a transaction flagged readOnly=true. Maybe it's just the way I've implemented it. I have a DAO class with @Transactional(readOnly = true) for all methods. One method is a SAVE, but I forgot to override to readOnly=false. I ran a test against the DAO and the transaction was rolled back, but I thought it should have failed because it was read only. Here's the setup:

    PersonDaoImplTest.java
    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath*:context.xml" })
    @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
    @Transactional
    public class PersonDaoImplTest {
        @Autowired
        PersonDao dao;
    
        @Test
        public void testSaveWithReadOnlyTrue() throws Exception {
            final Long personId = dao.savePerson(new Person("Steve"));
            assertIsNull(personId);
        }
    }
    context.xml
    Code:
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    
    	<context:component-scan base-package="com.example" />
    
    	<context:property-placeholder location="spring.properties" />
    
    	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close">
    		<property name="driverClassName" value="${jdbc.driver}" />
    		<property name="url" value="${jdbc.url}" />
    		<property name="username" value="${jdbc.username}" />
    		<property name="password" value="${jdbc.password}" />
    		<property name="defaultAutoCommit" value="false" />
    	</bean>
    	
    	<tx:annotation-driven transaction-manager="transactionManager" />
    	
    	<bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
    
    </beans>
    PersonDaoImpl.java
    Code:
    @Repository
    @Transactional(readOnly = true,propagation = Propagation.REQUIRED)
    public class PersonDaoImpl implements PersonDao {
    
    
        private JdbcTemplate jdbcTemplate;
    
    
        @Autowired
        @Override
        public void setDataSource(final DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }
    
    
        @Override
        public Long savePerson(final Person person) {
            final SqlUpdate insert = new SqlUpdate(jdbcTemplate.getDataSource(), "insert into person (name) values (?)");
            insert.declareParameter(new SqlParameter(Types.VARCHAR));
    
            insert.setGeneratedKeysColumnNames(new String[]{"ID" });
            insert.compile();
            final GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
            insert.update(
                    new Object[]{person.getName() }, keyHolder);
    
            return keyHolder.getKey().longValue();
        }
    }

  • #2
    I suggest a read of the test chapter and transaction chapter again....

    The testcase starts a transaction (not-readonly) and your dao simply uses this transaction. Also even if there would be no transaction there probably wouldn't be an exception as readonly is only an indication and forces nothing (I suggest a read of the jdbc driver specification). It only does something if the jdbc driver vendor has decided to act upon it, most simply ignore it.

    It makes more sense in a ORM world where the ORM provider (for instance hibernate) does some optimizations.

    Comment


    • #3
      Marten

      Thanks for the advice. I'll look @ the testing stuff again. I was just surprised the readonly was ignored for the test. In my debug logs I see the readonly registered in the transaction and it's enforced without the @Transactional in the test class. Here's my log
      Code:
      2012-10-27 13:53:54,142 DEBUG [AbstractFallbackTransactionAttributeSource.java:106] Adding transactional method 'test' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
      2012-10-27 13:53:54,143 DEBUG [TransactionalTestExecutionListener.java:148] Explicit transaction definition [PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''] found for test context [[TestContext@1a5f739 testClass = PersonDaoImplIT, testInstance = com.example.dao.PersonDaoImplIT@109fd93, testMethod = test@PersonDaoImplIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e6ff0d testClass = PersonDaoImplIT, locations = '{classpath*:context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
      2012-10-27 13:53:54,143 DEBUG [TransactionalTestExecutionListener.java:469] Retrieved @TransactionConfiguration [@org.springframework.test.context.transaction.TransactionConfiguration(defaultRollback=true, transactionManager=transactionManager)] for test class [class com.example.dao.PersonDaoImplIT]
      2012-10-27 13:53:54,144 DEBUG [TransactionalTestExecutionListener.java:486] Retrieved TransactionConfigurationAttributes [[TransactionConfigurationAttributes@1f1bd98 transactionManagerName = 'transactionManager', defaultRollback = true]] for class [class com.example.dao.PersonDaoImplIT]
      2012-10-27 13:53:54,144 DEBUG [TestContext.java:162] Retrieved ApplicationContext for test class [class com.example.dao.PersonDaoImplIT] from cache with key [[MergedContextConfiguration@e6ff0d testClass = PersonDaoImplIT, locations = '{classpath*:context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']].
      2012-10-27 13:53:54,144 DEBUG [AbstractBeanFactory.java:245] Returning cached instance of singleton bean 'transactionManager'
      2012-10-27 13:53:54,148 DEBUG [AbstractPlatformTransactionManager.java:365] Creating new transaction with name [test]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
      2012-10-27 13:53:54,420 DEBUG [DataSourceTransactionManager.java:204] Acquired Connection [jdbc:hsqldb:hsql://localhost:9001/tiber, UserName=SA, HSQL Database Engine Driver] for JDBC transaction
      2012-10-27 13:53:54,424 DEBUG [TransactionalTestExecutionListener.java:357] No method-level @Rollback override: using default rollback [true] for test context [[TestContext@1a5f739 testClass = PersonDaoImplIT, testInstance = com.example.dao.PersonDaoImplIT@109fd93, testMethod = test@PersonDaoImplIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e6ff0d testClass = PersonDaoImplIT, locations = '{classpath*:context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
      2012-10-27 13:53:54,424 INFO [TransactionalTestExecutionListener.java:275] Began transaction (1): transaction manager [[email protected]1642bd6]; rollback [true]
      2012-10-27 13:53:54,425 DEBUG [AbstractFallbackTransactionAttributeSource.java:106] Adding transactional method 'savePerson' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
      2012-10-27 13:53:54,426 DEBUG [AbstractBeanFactory.java:245] Returning cached instance of singleton bean 'transactionManager'
      2012-10-27 13:53:54,427 DEBUG [AbstractPlatformTransactionManager.java:470] Participating in existing transaction
      2012-10-27 13:53:54,430 DEBUG [RdbmsOperation.java:343] RdbmsOperation with SQL [INSERT INTO PERSON (NAME) VALUES (?)] compiled
      2012-10-27 13:53:54,432 DEBUG [JdbcTemplate.java:841] Executing SQL update and returning generated keys

      Comment

      Working...
      X