标签:
一、Spring事务管理
在JavaEE分层开发中,事务管理代码放到业务层
1、 事务管理相关API
PlatformTransactionManager 平台事务管理器
* void commit(TransactionStatus status) 提交事务
* TransactionStatus getTransaction(TransactionDefinition definition) 根据事务定义信息,获得当前状态
* void rollback(TransactionStatus status) 回滚事务
TransactionDefinition 事务定义信息 (配置信息 来自xml配置文件 和 注解)
包括 (隔离、传播、超时、只读)
* ISOLATION_xxx 事务隔离级别
* PROPAGATION_xxx 事务传播行为
* int getTimeout() 获得超时信息
* boolean isReadOnly() 判断事务是否只读
TransactionStatus 事务具体运行状态
* 每一个时刻点 事务具体状态信息
关系: PlatformTransactionManager 根据 TransactionDefinition 进行事务管理, 管理过程中事务存在多种状态, 每个状态信息通过 TransactionStatus 表示
2、 PlatformTransactionManager 接口详解
1) 不同平台事务管理器实现
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或iBatis 进行持久化数据时使用
org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate3.0版本进行持久化数据时使用
org.springframework.orm.jpa.JpaTransactionManager 使用JPA进行持久化时使用
org.springframework.jdo.JdoTransactionManager 当持久化机制是Jdo时使用
org.springframework.transaction.jta.JtaTransactionManager 使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用
* 针对不同持久层技术,选用对应事务管理器
2) TransactionDefinition 事务隔离级别
事务四大特性 : ACID 原子性、一致性、隔离性、持久性
隔离性引发并发问题: 脏读、 不可重复读、 虚读
* 脏读 一个事务读取另一个事务 未提交数据
* 不可重复读 一个事务读取另一个事务 已经提交 update 数据
* 虚读 一个事务读取另一个事务 已经提交 insert 数据
事务隔离级别 为了解决 事务隔离性引发 问题
* DEFAULT 默认级别 mysql REPEATABLE_READ 、 oracle READ_COMMITTED
* READ_UNCOMMITED 导致所有问题发生
* READ_COMMITTED 防止脏读、 发生不可重复读和虚读
* REPEATABLE_READ 防止脏读、不可重复读,发生虚读
* SERIALIZABLE 防止所有并发问题
3) TransactionDefinition 事务的传播行为
* 不是JDBC 规范定义
* 传播行为 针对实际开发中问题
传播行为解决问题: 一个业务层事务 调用 另一个业务层事务,事务之间关系如何处理
七种传播行为
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个
* 删除客户 删除订单, 处于同一个事务,如果 删除订单失败,删除客户也要回滚
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
* 生成订单, 发送通知邮件, 通知邮件会创建一个新的事务,如果邮件失败, 不影响订单生成
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
* 依赖于 JDBC3.0 提供 SavePoint 技术
* 删除客户 删除订单, 在删除客户后, 设置SavePoint, 执行删除订单,删除订单和删除客户在同一个事务 ,删除订单失败, 事务回滚 SavePoint , 由用户控制是事务提交 还是 回滚
重点:
PROPAGATION_REQUIRED 一个事务, 要么都成功,要么都失败
PROPAGATION_REQUIRES_NEW 两个不同事务,彼此之间没有关系 一个事务失败了 不影响另一个事务
PROPAGATION_NESTED 一个事务, 在A事务 调用 B过程中, B失败了, 回滚事务到 之前SavePoint , 用户可以选择提交事务或者回滚事务
=================================================================================================================================
3、 Spring 事务管理方式
1) 编程式 事务管理 (了解)
在代码中 通过 TransactionTemplate 手动进行事务管理 ,在实际开发中很少被用到
2) 声明式 事务管理
在配置文件中,对Bean的方法进行事务管理, 基于AOP思想 ,无需写代码, 开发中主流使用
4、 Spring 通过编程式 进行事务管理
第一步: 创建账户数据表
CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `money` double DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; INSERT INTO `account` VALUES (‘1‘, ‘aaa‘, ‘1000‘); INSERT INTO `account` VALUES (‘2‘, ‘bbb‘, ‘1000‘);
第二步 : 编写转账操作程序 (数据库操作 JdbcTemplate )
AccountServiceImpl public class AccountServiceImpl implements AccountService { // 在Service中注入DAO private AccountDAO accountDAO; @Override public void transfer(String outAccount, String inAccount, double money) { accountDAO.outMoney(outAccount, money); accountDAO.inMoney(inAccount, money); } public void setAccountDAO(AccountDAO accountDAO) { this.accountDAO = accountDAO; } }
AccountDAOImpl public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO { @Override public void outMoney(String outAccount, double money) { String sql = "update account set money = money-? where name = ?"; this.getJdbcTemplate().update(sql, money, outAccount); } @Override public void inMoney(String inAccount, double money) { String sql = "update account set money = money + ? where name = ?"; this.getJdbcTemplate().update(sql, money, inAccount); } }
配置applicationContext.xml <!-- 导入外部属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 数据库连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 业务层 --> <bean id="accountService" class="cn.itcast.spring.transaction.a_programing.AccountServiceImpl"> <property name="accountDAO" ref="accountDAO"></property> </bean> <!-- DAO --> <bean id="accountDAO" class="cn.itcast.spring.transaction.a_programing.AccountDAOImpl"> <!-- 将连接池注入给DAO ,JdbcDaoSupport 自动创建 JdbcTemplate对象 --> <property name="dataSource" ref="dataSource"></property> </bean>
*********** 如果没有使用任何事务管理 , JdbcTemplate DAO 每个操作 就是单独的事务
第三步 : 在AccountService 中注入 TransactionTamplate 事务管理模板 ,完成事务管理
<!-- 事务管理模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <!-- 将管理器 注入给 模板 --> <property name="transactionManager" ref="transactionManager"></property> </bean> <!-- 事务管理器 --> <!-- org.springframework.jdbc.datasource.DataSourceTransactionManager 用来管理 jdbc操作事务的 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 将连接池 注入给事务管理器 --> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountService" class="cn.itcast.spring.transaction.a_programing.AccountServiceImpl"> <property name="accountDAO" ref="accountDAO"></property> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean>
第四步 :使用TransactionTemplate 进行事务管理
public void transfer(final String outAccount, final String inAccount, final double money) { // 使用 事务模板 管理事务 transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult( TransactionStatus transactionStatus) { accountDAO.outMoney(outAccount, money); int d = 1 / 0; accountDAO.inMoney(inAccount, money); } }); }
================================================================================================================
在实际开发中,因为编程式事务管理 存在代码侵入,所有不常使用, 通常通过 声明式事务管理
5、 通过TransactionProxyFactoryBean 对业务类创建代理,实现声明式事务管理
*无需修改Service代码
*通过applicationContext.xml 配置为AccountService 对象创建代理
必须配置事务管理器
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
为目标Service创建代理
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 目标 --> <property name="target" ref="accountService"></property> <!-- 针对接口代理 --> <property name="proxyInterfaces" value="cn.itcast.spring.transaction.b_transactionproxyfactorybean.AccountService"></property> <!-- 增强 事务管理--> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributes"> <!-- 事务管理属性 --> <!-- 针对目标对象 每个方法 ,设置隔离级别、传播行为、是否只读 --> <props> <!-- key就是方法名 --> <!-- value prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception --> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
使用该方式,在Test程序中,注入代理对象
public class AccountServiceTest {
@Autowired
@Qualifier("accountServiceProxy") // 注入代理对象
private AccountService accountService;
...
}
事务属性设置 prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
PROPAGATION 事务传播行为
ISOLATION, 事务隔离级别
readOnly 表示事务是只读的,不能进行修改操作
-Exception 发生这些异常事务进行回滚 (默认发生任何异常事务都会回滚)
+Exception 事务将忽略这些异常,仍然提交事务
*** 基于TransactionProxyFactoryBean 创建代理对象,进行事务管理,缺点需要为 每个Bean 都创建单独代理对象,开发量巨大
6、 基于tx配置 ,为目标对象进行自动代理 (重点 )
在applicationContext.xml 引入 tx 和 aop 两个名词空间
<!-- 使用tx定义 事务管理增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 方法的事务管理属性 --> <tx:attributes> <!-- name="transfer" 事务管理方法名 isolation="DEFAULT" 默认隔离级别 propagation="REQUIRED" 默认传播行为 read-only="false" 是否只读 no-rollback-for="" 发生异常不会滚 类似+Exception rollback-for="" 发生异常回滚 类似-Exception timeout="-1" 不超时 --> <tx:method name="transfer"/> </tx:attributes> </tx:advice>
<!-- 使用Aop 进行自动代理 --> <aop:config> <!-- 定义切点 --> <aop:pointcut expression="execution(* cn.itcast.spring.transaction.c_txconfig.AccountService+.*(..))" id="mypointcut"/> <!-- 定义切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/> </aop:config>
*** 定义 事务管理 tx:advice 将增强代码 应用切点上
7、 基于注解的声明式事务管理 (重点)
第一步 :在需要管理事务 类或者方法 上添加 @Transactional
第二步: 在applicationContext.xml 配置
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 注解事务管理 --> <tx:annotation-driven transaction-manager="transactionManager"/>
配置事务属性 通过@Transactional配置
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, readOnly = false, noRollbackFor = ArithmeticException.class, rollbackFor = NullPointerException.class, timeout = -1)
* isolation 隔离级别
* propagation 传播行为
* readOnly 是否只读
* noRollbackFor 发生异常不回滚
* rollbackFor 发生异常回滚
* timeout 超时时间 -1 不超时
标签:
原文地址:http://www.cnblogs.com/chentaiyan/p/4471662.html