1. 基于xml的事务声明控制
1.1 什么是事务声明控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
作用:
- 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
注意:Spring 声明式事务控制底层就是AOP。
接下来,我们使用转账的例子进行说明。
1.2 为什么要声明式事务控制
基础环境准备:在dao层实现往账户入账和出账的方法,在service实现转账方法,在controller调用转账方法进行模拟转账功能。
dao层:
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void out(String outMan, double money) {
jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
}
public void in(String inMan, double money) {
jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
}
}
service层:
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
//int i = 1/0;
accountDao.in(inMan,money);
}
}
controller层:
public class AccountController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = app.getBean(AccountService.class);
accountService.transfer("Adrian","Young",500);
}
}
在数据库中创建account表。
接下来我们运行程序,实现转账。看表中数据变化:
可以看出,转账成功实现。
但是,如果转账时候出现异常,会出现什么结果呢,这里我们设置一个自杀式异常
运行程序,看数据库中表的变化
可以看出,出账成功,入账失败,500块钱凭空消失了。因此我们需要使用事务进行控制转账流程,避免上述情况出现。
1.3 声明式事务控制的实现
- 配置平台事务管理器
<!--配置平台事务管理器 因为事务的增强那一块需要平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- 配置通知 即事务的增强
<!--通知 事务的增强 tx:事务控制的命名空间-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--设置事务的属性信息的-->
<tx:attributes>
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
<tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
<!-- 哪些方法需要被增强 *代表任意-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
- 配置事务的aop织入
<!--配置事务的aop织入-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.ex1.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
接下来,我们运行上次同样的程序
可以看出,程序出现报错,但是,数据库中的数据并没有改变,说明事务成功帮助我们解决了数据丢失问题。
接下来,我们把自杀式错误关闭,运行程序:
可以看出,转账进行成功。
总结:
2. 基于注解的事务声明控制
2.1 使用注解的事务声明控制
首先,使用注解需进行包扫描,这时,首先的引入context命名空间下的包扫描
<context:component-scan base-package=“com.ex1”></context:component-scan>
对accountDao和accountService使用注解进行注入
@Repository(“accountDao”)
@Service(“accountService”)
同时,对accountDao类和accountService类下的成员变量使用@Autowired进行注入
对需要事务控制的切点(方法)使用@Transactional进行注入
当然,也可以在该方法的类上使用@Transactional进行注入,这种方法则表明对该类下的所有方法都进行 事务控制。
接下来,配置平台事务管理器
<!--配置平台事务管理器 因为事务的增强那一块需要平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
最后,配置事务注解驱动
<tx:annotation-driven transaction-manager="transactionManager"/>
以上,就是使用注解来控制事务声明的方法步骤。