spring事务管理的API
platfformTransactionManager 平台事务管理器
平台事务管理器: 接口 是spring用于管理事务的真正的对象
DataSourceTransactionManager: 底层使用JDBC管理事务
HibernateTransactionManager: 底层使用Hibernate管理事务
TransactionDefinition 事务定义信息
事务定义: 接口 是用于定义事务的相关信息 隔离级别 超时信息 传播行为 是否只读
TransactionStatus 事务的状态
事务的状态 用于记录在事务管理过程中 事务的状态的对象
API之间的关系
spring进行事务管理的时候,首先将平台事务管理器根据事务定义信息进行事务的管理 在事务管理过程中,产生各种状态,将这些状态记录到事务状态的对象中
spring的事务传播行为
事务传播行为产生的原因
一般事务发生在service层(会调用dao),为了解决复杂业务中业务层之间方法相互调用,而每个service又有自己的事务,一个业务中出现了多个事务,就出现了传播行为。
例A:
Class Dao1 {
void da() {}
}
Class Dao2 {
void db() {}
}
Class Service1 {
@Autowired
Dao1 dao;
void sa() {
dao.da()
}
}
Class Service2 {
@Autowired
Service2 service;
@Autowired
Dao2 dao2;
void sb() {
service.sa();
dao2.db();
}
}
我们可以看到在service1是有自己的事务的,service2也是有自己的事务的,那么就出现了sb方法中,一个业务两种事务,就产生了传播。
spring中提供了七种事务传播行为
保证多个操作在同一个事务中
下表中的含义根据上文中例A的代码来解释
传播行为 | 含义 |
---|---|
propagation_required | 默认值 如果sa中有事务 则使用sa中的事务,如果sa没有 创建一个新的事务 将操作(dao2.db)包含进来 |
propagation_supports | 支持事务, 如果sa中有事务,使用sa中的事务。如果sa没有事务 不使用事务 |
propagation_mandatory | 如果sa中有事务 使用sa中的事务 如果sa中没有事务 -抛异常 |
保证多个操作不再同一个事务中
传播行为 | 含义 |
---|---|
propagation_required_new | 如果sa中有事务,将sa中的事务挂起 创建新的事务 只包含自身操作 如果sa中没有事务 创建一个新的事务包含自身操作 |
propagation_not_support | 如果sa中有事务 将sa中的事务挂起 不再使用事务 |
propagation_never | 如果sa中有事务 报异常 |
嵌套式事务
传播行为 | 含义 |
---|---|
propagation_nested | 嵌套事务 如果sa中有事务,按照sa的事务执行,执行完成后,设置一个保存点 执行dao2.db()中的操作 如果没有异常 执行通过 如果有异常 可以选择回滚到最初的位置 也可以回滚到保存点 |
Spring中事务应用
以A给B转帐的例子来看事务,转帐这一个操作可以分为两个步骤:A的账户减少转帐金额,B的账户增加转帐金额,任何一个步骤出错,这一个操作都应该失败,这样理解起来AB转帐这个操作应该需要使用事务。
创建数据库的表
create table account (
name char(20),
money double(5,2)
);
编程式事务管理 —通过代码实现
第一步 在POM文件中引入环境相关的依赖
第二步 在spring配置文件中配置平台事务管理器和平台事务管理模板
第三步 在业务层使用平台事务管理模板实现事务
spring配置文件 tx.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置service -->
<bean id="accountService" class="com.demo.tx.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
<bean id="accountDao" class="com.demo.tx.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置c3p0的连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置平台事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
</beans>
数据持久层dao的接口类和实现类
接口类:AccountDao.java
package com.demo.tx;
public interface AccountDao {
public void transferOutMoney(String from, Double money);
public void transferInMoney(String to, Double money);
}
实现类:AccountDaoImpl.java----利用spring中的jdbcTemplate
package com.demo.tx;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
/* (non-Javadoc)
* @see com.demo.tx.AccountDao#transferOutMoney(java.lang.String, java.lang.Double)
*/
public void transferOutMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
}
/* (non-Javadoc)
* @see com.demo.tx.AccountDao#transferInMoney(java.lang.String, java.lang.Double)
*/
public void transferInMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
}
}
业务层的接口和实现类
AccountService.java
package com.demo.tx;
public interface AccountService {
/**
* @param from 转出
* @param to 转入
* @param money 金额
*/
public void transfer(String from, String to, Double money);
}
AccountServiceImpl.java
package com.demo.tx;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
public class AccountServiceImpl implements AccountService {
/* (non-Javadoc)
* @see com.demo.tx.AccountService#transfer(java.lang.String, java.lang.String, java.lang.Double)
*/
private AccountDao accountDao;
/**
* @param accountDao the accountDao to set
*/
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
// 注入事务管理的模板
private TransactionTemplate transactionTemplate;
/**
* @param transactionTemplate the transactionTemplate to set
*/
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(final String from, final String to, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.transferInMoney(to, money);
accountDao.transferOutMoney(from, money);
}
});
}
}
声明式事务管理 —通过配置实现 底层通过aop实现
第一步 在POM文件中引入相关依赖
第二步 在spring的配置文件中配置平台事务管理器
第三步 在spring的配置文件中配置增强
实现声明式事务的两种方式:XML方式和注解方式
实现事务的XML方式
在spring配置文件中增加
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务的增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
<!--
一般find方法不需要事务
<tx:method name="find" read-only="true"/> -->
</tx:attributes>
</tx:advice>
<!-- aop的配置 -->
<aop:config>
<aop:pointcut expression="execution(* com.demo.tx2.AccountServiceImpl.*(..))" id="pointcut1"/>
<!-- 一个切面一个切点 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
<!-- 多个切面多个切点 -->
</aop:config>
修改AccountServiceImpl.java
package com.demo.tx2;
public class AccountServiceImpl implements AccountService {
/* (non-Javadoc)
* @see com.demo.tx.AccountService#transfer(java.lang.String, java.lang.String, java.lang.Double)
*/
private AccountDao accountDao;
/**
* @param accountDao the accountDao to set
*/
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String from, String to, Double money) {
accountDao.transferInMoney(to, money);
// int i=1/0;
accountDao.transferOutMoney(from, money);
}
}
实现事务的注解方式: @Transactional
标注在类前:标示类中所有方法都进行事务处理
标注在接口、实现类的方法前:标示方法进行事务处理
pom.xml文件、数据持久层dao层同编程式事务
在spring 配置文件中增加
<!-- 配置事务管理器=============================== -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启注解事务================================ -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
在Service的实现类中增加@Transactional注解,@Transactional可以标注在类前,也可以标注在方法前,里面可以设置隔离级别,事务传播等内容。
标注在类前:标示类中所有方法都进行事务处理
标注在接口、实现类的方法前:标示方法进行事务处理
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
测试效果:
在AccountServiceImp.java的transfer方法中没有出现异常时,转帐正常。
如果没有事务时,在转出成功之后,转入之前出现异常,则转出成功,转入失败,而我们需要两个操作都失败,加上事务之后,只要发生异常,整个操作就会失败