Here is a comprehensive working example using JavaConfig (uses standalone HSQL server with a simple foo table). This java configuration can be further simplified if you use annotation driven transactions (not included in this sample).
Code:
import org.springframework.transaction.interceptor.TransactionProxyFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.config.java.annotation.Bean;
import org.springframework.config.java.annotation.Configuration;
import org.springframework.config.java.context.JavaConfigApplicationContext;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.junit.Test;
import javax.sql.DataSource;
import java.util.Properties;
import java.sql.SQLException;
import java.sql.ResultSet;
import static junit.framework.Assert.assertEquals;
public class TestTransactionConfig {
@Test
public void testFooService() throws Exception {
JavaConfigApplicationContext context = new JavaConfigApplicationContext(TransactionConfig.class);
DefaultFooService fooService = context.getBean(DefaultFooService.class);
Foo myFoo = new Foo();
myFoo.setName("myFoo");
fooService.insertFoo(myFoo);
assertEquals("myFoo", fooService.getFoo(0).getName());
}
@Configuration
static class TransactionConfig {
@Bean
public TransactionProxyFactoryBean baseProxy() {
TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
Properties transactionAttributes = new Properties();
transactionAttributes.setProperty("save", "PROPAGATION_REQUIRED");
transactionAttributes.setProperty("update", "PROPAGATION_REQUIRED");
transactionAttributes.setProperty("delete", "PROPAGATION_REQUIRED");
transactionProxyFactoryBean.setTransactionAttributes(transactionAttributes);
transactionProxyFactoryBean.setTarget(fooService());
transactionProxyFactoryBean.setTransactionManager(transactionManager());
return transactionProxyFactoryBean;
}
@Bean
public DefaultFooService fooService() {
DefaultFooService fooService = new DefaultFooService();
fooService.setFooDao(fooDao());
return fooService;
}
@Bean
public DefaultFooDao fooDao() {
DefaultFooDao fooDao = new DefaultFooDao();
fooDao.setDataSource(dataSource());
return fooDao;
}
@Bean
public PlatformTransactionManager transactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource());
return transactionManager;
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:9001");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
}
static class Foo {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface FooService {
Foo getFoo(int id);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
void deleteFoo(int id);
}
public interface FooDao {
void create(Foo foo);
Foo read(int id);
void update(Foo foo);
void delete(int id);
}
static class DefaultFooDao implements FooDao {
public DefaultFooDao() {
}
private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertFoo;
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
this.insertFoo = new SimpleJdbcInsert(dataSource)
.withTableName("foo")
.usingGeneratedKeyColumns("id");
}
public void create(Foo foo) {
Number newKey = this.insertFoo.executeAndReturnKey(
createFooParameterSource(foo));
foo.setId(newKey.intValue());
}
public Foo read(int id) {
Foo foo;
try {
foo = this.simpleJdbcTemplate.queryForObject(
"SELECT id, name FROM foo WHERE id=?",
new JdbcPetRowMapper(),
id);
}
catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Foo.class, id);
}
return foo;
}
public void update(Foo foo) {
throw new UnsupportedOperationException();
}
public void delete(int id) {
throw new UnsupportedOperationException();
}
private MapSqlParameterSource createFooParameterSource(Foo foo) {
return new MapSqlParameterSource()
.addValue("id", foo.getId())
.addValue("name", foo.getName());
}
private class JdbcPetRowMapper implements ParameterizedRowMapper<Foo> {
public Foo mapRow(ResultSet rs, int rownum) throws SQLException {
Foo foo = new Foo();
foo.setId(rs.getInt("id"));
foo.setName(rs.getString("name"));
return foo;
}
}
}
static class DefaultFooService implements FooService {
public DefaultFooService() {
}
private FooDao fooDao;
public void setFooDao(FooDao fooDao) {
this.fooDao = fooDao;
}
public Foo getFoo(int id) {
return fooDao.read(id);
}
public void insertFoo(Foo foo) {
fooDao.create(foo);
}
public void updateFoo(Foo foo) {
fooDao.update(foo);
}
public void deleteFoo(int id) {
fooDao.delete(id);
}
}
}
Hope this helps.
-Arul