事务的管理有几种方式, 使用注解, 声明式配置等等.
首先,看一下单一数据源的事务配置:
xmlns:tx="http://www.springframework.org/schema/tx"
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">
其中transactionInterceptor中配置的拦截方法就是需要事务管理的, 满足命名条件的方法都会被事务管理所拦截.
测试:
/* Dao代码 */
public class JdbcTestDao {
@Resource(name="jdbctemplate")
JdbcTemplate jdbcTemplate;
/**
* 在配置文件中使用了声明式的事务管理,
* 所以这个事务是会被拦截的事务
*/
public void execute(){
jdbcTemplate.update("UPDATE user set username = 'fff1' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'eee1' where id=4");
int i = 1/0;
}
/**
* 这个虽然不是在配置文件中需要被拦截的事务,但是有注解声明
* 所以这个事务是会被拦截的事务
*/
@Transactional
public void notExtcuteWithTx(){
jdbcTemplate.update("UPDATE user set username = 'ggg' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'hhh' where id=4");
int i = 1/0;
}
/**
* 不会被拦截的事务
*/
public void notExtcute(){
jdbcTemplate.update("UPDATE user set username = 'iii' where id=4");
jdbcTemplate.update("UPDATE user1 set username = 'jjjj' where id=4");
int i = 1/0;
}
}
/* jUnit代码 */
public class JdbcTestDaoTest {
ApplicationContext context;
@Before
public void before() {
context = new ClassPathXmlApplicationContext("spring-jdbc.xml");
}
@Test
public void execute() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.execute();
}
@Test
public void notExtcuteWithTx() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.notExtcuteWithTx();
}
@Test
public void notExtcute() {
JdbcTestDao dao = context.getBean(JdbcTestDao.class);
dao.notExtcute();
}
}
分别单元测试三个方法, 可以得到正确的结果, 当抛出异常的时候, 事务都会回滚.
二.多数据源的事务管理
在spring中, 提供了很多事务管理的接口, DataSourceTransactionManager, JpaTransactionManager, JtaTransactionManager等等. 其中JtaTransactionManager是专门用来管理多数据源, 提供了对分布式事务的支持.
xmlns:tx="http://www.springframework.org/schema/tx"
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">
这里,使用的都是mysql, 只是数据库不同, 也可以使用多种数据库,可替换为oracle等.
测试:
/* Dao代码 */
@Component
public class JtaTestDao implements ApplicationContextAware ,InitializingBean{
private ApplicationContext context;
public void execute() {
JdbcTemplate chatroom = context.getBean("jdbctemplate1",
JdbcTemplate.class);
JdbcTemplate cms = context.getBean("jdbctemplate2",
JdbcTemplate.class);
chatroom.update("UPDATE user set username = 'lzxfgw' where id=4");
cms.update("INSERT INTO c_user (id, login_name, password) values (100, 'fgw', '123')");
}
//@PostConstruct
//实现ApplicationContextAware接口, 可以在初始化的时候注入applicationContext
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
}
}
/* jUnit代码 */
public class JtaTestDaoTest {
ApplicationContext context;
@Test
public void test() {
JtaTestDao t = context.getBean(JtaTestDao.class);
t.execute();
}
@Before
public void before() {
context = new ClassPathXmlApplicationContext("spring-jta.xml");
}
}
运行jUnit第一次是没有问题的, 修改一下dao代码中的username再次运行,会抛出主键重复的异常, 可以看到数据库中的第一条update语句的username也没有改变, 说明事务在抛出异常之后正常回滚了.