Spring 事务管理


在数据库操作中事务管理是一个重要的概念,例如银行转账。

Spring的事务管理简化了传统的数据库事务管理流程,提高了开发效率。

1.编程式事务管理

在代码中显示调用beginTransaction、commit、rollback 等与事务处理相关的方法,这就是编程式事务管理。当只有少数事务操作时,编程式事务管理才比较合适。

基于底层API的编程式事务管理

基于 TransactionTemplate 的编程式事务管理

2.声明式事务管理

Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务。

声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明便可以将事务规则应用到业务逻辑中。

使用声明式事务管理不仅因为其简单,更主要的是可以使得纯业务代码不被污染,极大的方便了后期的代码维护。

与编程式事务管理相比,唯一不足的是:最细粒度只能作用到方法级别,无法像编程式那样可以作用到代码块级别。(不过可以通过变通的方法解决,比如将需要进行事务处理的代码块独立为方法等)。

Spring的声明式事务管理通过两种方式实现:XML、@Transactional 注解

2.1 基于XML

创建Dao层

package com.statement.dao;
public interface TestDao {
    public int save(String sql, Object param[]);
    public int delete(String sql, Object param[]);
}
package com.statement.dao;
@Repository("TestDao")
public class TestDaoImpl implements TestDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public int save(String sql, Object[] param) {
        return jdbcTemplate.update(sql, param);
    }
    @Override
    public int delete(String sql, Object[] param) {
        return jdbcTemplate.update(sql, param);
    }
}

创建Service层,依赖注入数据访问层。

package com.statement.service;
public interface TestService {
    public int save(String sql, Object param[]);
    public int delete(String sql, Object param[]);
}
package com.statement.service;
@Service("testService")
public class TestServiceImpl implements TestService {
    @Autowired
    private TestDao testDao;
    @Override
    public int save(String sql, Object[] param) {
        return testDao.save(sql, param);
    }
    @Override
    public int delete(String sql, Object[] param) {
        return testDao.delete(sql, param);
    }
}

创建Controller层,依赖注入Service层。

package com.statement.controller;
@Controller("statementController")
public class StatementController {
    @Autowired
    private TestService testService;
    public String test() {
        String message="";
        String deleteSql="delete from user";
        String saveSql="insert into user values(?,?,?)";
        Object param[]={1,"chen","男"};
        try{
            testService.delete(deletSql, null);
            testService.save(saveSql, param);
            testService.save(saveSql, param);
        }catch(Exception e) {
            message="主键重复,事务回滚!";
            e.printStackTrace();
        }
        return message;
    }
}

创建配置文件

<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!-- 编写通知声明事务 -->
<tx:advice id="myAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!-- *表示任意方法 -->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
<!-- 编写AOP,让Spring自动对目标对象生成代理,需要使用AspectJ的表达式 -->
<aop:config>
    <!-- 定义切入点 -->
    <aop:pointcut expression="execution(* com.statement.sservice.*.*())" id="txPointCut"/>
    <!-- 切面:将切入点与通知关联 -->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
</aop:config>

创建测试类

package com.statement.test;
public class Test {
    public static void main(String[] args) {
        ApplicationContext appCon=new ClassPathXmlApplicationContext("/com/statement/applicationContext.xml");
        StatementController ct=(StatementController)appCon.getBean("statementController");
        String result=ct.test();
        System.out.println(result);
    }
}

运行结果:
主键重复,事务回滚!

2.2 基于@Transactional

@Transactional 可以作用于接口、接口方法、类、类的方法上。

当作用于类上时,该类的所有public方法都将具有该类型的事务属性,同时也可以在方法级别使用该注解来覆盖类级别的定义。

Spring小组不建议在接口或接口方法上使用该注解,因为它只有在使用基于接口的代理时才会生效。

Dao、Service、Controller层相同,仅展示修改的部分代码。

配置文件

<!-- 为数据源添加事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 为事务管理器注册注解驱动器 -->
<tx:annotation-driven transaction-manager="txManager"/>

Spring MVC通常在Service层进行事务管理。

package com.statement.service;
@Service("testService")
@Transactional
// 指定这个类需要接受Spring的事务管理
// 只能针对public属性范围内的方法
public class TestServiceImpl implements TestService {

  TOC