Skip to content

ChainedTransactionManager integration tests #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,32 @@
<artifactId>spring-oxm</artifactId>
<optional>true</optional>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.174</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>


<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.springframework.data.transaction;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.transaction.service.AuditService;
import org.springframework.data.transaction.service.FooService;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* Some integration tests to test the ChainedTransactionManager
*
* Currently there are two simple tests that are functionally the same apart from the methods to count the rows in the tables
* using different transaction propagation.
*
*
* The second test testCountFoosWithNotSupportedTransactionPropagationFollowedByCreateAFoo() fails with an exception
*
* CannotCreateTransactionException - Could not open JDBC Connection for transaction;
* nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@d2de489]
* for key [org.apache.commons.dbcp.BasicDataSource@3f4faf53] bound to thread [main]
*
* TJ - I think there is an issue with the ChainedTransactionManager possibly in the getTransaction() method where the synchronizationManager
* is initialised regardless of the transaction propagation. Compare this with AbstractPlatformTransactionManager.getTransaction()
* where initSynchronization() would only be called for transaction propagation of REQUIRED, REQUIRES_NEW and NESTED
*
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/META-INF/spring/transaction/data-source-context.xml")
public class ChainedTransactionManagerIntegrationTests {

private static final Logger logger = LoggerFactory.getLogger(ChainedTransactionManagerIntegrationTests.class);

@Autowired
private FooService fooService;

@Autowired
private AuditService auditService;



@Before
public void clearData() {

fooService.deleteFoos();

auditService.deleteAudits();

}


/**
* A simple test that
*
* 1) counts the number of rows in table T_FOOS then
*
* 2) inserts one row into table T_FOOS then
*
* 3) re-counts the number of rows in table T_FOOS
*
*
* Note that the method to count the rows in table T_FOOS are advised with REQUIRED transaction propagation
*
*/
@Test
public void testCountFoosWithRequiredTransactionPropagationFollowedByCreateAFoo() {

logger.debug("======== Test count Foos (with REQUIRED transaction propagation) followed by creating a Foo ==========");

int countFoos = fooService.countFoosWithRequiredTransactionPropagation();

logger.debug(countFoos + " rows of data in table T_FOOS");
assertEquals("There should be 0 rows in table T_FOOS", 0, countFoos);

fooService.createAFoo();

countFoos = fooService.countFoosWithRequiredTransactionPropagation();

logger.debug(countFoos + " rows of data in table T_FOOS");
assertEquals("There should be one row in table T_FOOS", 1, countFoos);

}


/**
* This test is the same as the test above testCountFoosWithRequiredTransactionPropagationFollowedByCreateAFoo() except
* the the method to count the rows in table T_FOOS are advised with NOT_SUPPORTED transaction propagation (rather than REQUIRED)
*
* A simple test that
*
* 1) counts the number of rows in table T_FOOS then
*
* 2) inserts one row into table T_FOOS then
*
* 3) re-counts the number of rows in table T_FOOS
*
*
* Currently this test fails with the following exception:
*
* org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@d2de489] for key [org.apache.commons.dbcp.BasicDataSource@3f4faf53] bound to thread [main]; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@d2de489] for key [org.apache.commons.dbcp.BasicDataSource@3f4faf53] bound to thread [main]
* at org.springframework.data.transaction.ChainedTransactionManager.getTransaction(ChainedTransactionManager.java:122)
* at org.springframework.data.transaction.ChainedTransactionManager.getTransaction(ChainedTransactionManager.java:1)
* .
* .
* .
*
*/
@Test
public void testCountFoosWithNotSupportedTransactionPropagationFollowedByCreateAFoo() {

logger.debug("======== Test count Foos (with NOT_SUPPORTED transaction propagation) followed by creating a Foo ==========");

int countFoos = fooService.countFoosWithNotSupportedTransactionPropagation();

logger.debug(countFoos + " rows of data in table T_FOOS");
assertEquals("There should be 0 rows in table T_FOOS", 0, countFoos);

fooService.createAFoo();

countFoos = fooService.countFoosWithNotSupportedTransactionPropagation();

logger.debug(countFoos + " rows of data in table T_FOOS");
assertEquals("There should be one row in table T_FOOS", 1, countFoos);

}




}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.springframework.data.transaction.service;

public interface AuditService {

public int countAudits();


public void createAudit();


public void deleteAudits();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.springframework.data.transaction.service;

public interface FooService {

public int countFoosWithNotSupportedTransactionPropagation();


public int countFoosWithRequiredTransactionPropagation();


public void createAFoo();


public void updateAFoo();


public void deleteFoos();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.springframework.data.transaction.service.impl;

import java.util.Date;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.transaction.service.AuditService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class AuditServiceImpl implements AuditService {

private static final Logger logger = LoggerFactory.getLogger(AuditService.class);

private JdbcTemplate jdbcTemplate;


@Autowired
public void setDataSources(@Qualifier("secondDataSource") DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}


@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public int countAudits() {

int count = jdbcTemplate.queryForObject("select count(*) from T_AUDITS", Integer.class);

return count;

}


@Transactional(propagation = Propagation.REQUIRED)
@Override
public void createAudit() {

logger.debug("inserting a row into table T_AUDITS");
jdbcTemplate.update(
"INSERT into T_AUDITS (id,operation,name,audit_date) values (?,?,?,?)",
0, "INSERT", "foo", new Date());

}


@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void deleteAudits() {

logger.debug("deleting all data from table T_AUDITS");
jdbcTemplate.update("delete from T_AUDITS");

}





}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.springframework.data.transaction.service.impl;

import java.util.Date;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.transaction.service.FooService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class FooServiceImpl implements FooService {

private static final Logger logger = LoggerFactory.getLogger(FooService.class);

private JdbcTemplate jdbcTemplate;


@Autowired
public void setDataSources(@Qualifier("firstDataSource") DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}


@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public int countFoosWithNotSupportedTransactionPropagation() {

int count = jdbcTemplate.queryForObject("select count(*) from T_FOOS", Integer.class);

return count;

}


@Transactional(propagation = Propagation.REQUIRED)
@Override
public int countFoosWithRequiredTransactionPropagation() {

int count = jdbcTemplate.queryForInt("select count(*) from T_FOOS");

return count;

}



@Transactional(propagation = Propagation.REQUIRED)
@Override
public void createAFoo() {

logger.debug("inserting a row into from table T_FOOS");
jdbcTemplate.update(
"INSERT into T_FOOS (id,name,foo_date) values (?,?,null)", 0,
"foo");

}


@Transactional(propagation = Propagation.REQUIRED)
@Override
public void updateAFoo() {

logger.debug("updating a row in table T_FOOS");
jdbcTemplate.update(
"UPDATE T_FOOS set name = ? WHERE id = 0", "an updated foo " + new Date());

}


@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void deleteFoos() {

logger.debug("deleting all data from table T_FOOS");
jdbcTemplate.update("delete from T_FOOS");

}


}
Loading