SPRing事务管理
@(Spring)[spring, 事务管理, 事务, Spring]
Spring事务管理事务的基本概念什么是事务事务的特性事务的隔离性不完善引发的问题设置隔离级别解决读问题Spring的事务管理Spring事务管理的APISpring的事务传播行为Spring的事务管理案例环境搭建Spring的事务管理的分类创建相关接口和类并配置注解配置Spring在DAO中使用JDBC的模板编写测试类Spring的声明式事务管理xml方式的声明式事务配置事务管理器配置一个事务通知配置AOPtxmethod的配置注解方式的声明式事务配置事务管理器开启注解事务在业务层添加一个事务的注解Transactional的配置Spring的编程式事务管理配置事务管理器配置事务管理的模板简化事务开发在业务层注入事务管理的模板进行事务管理TransactionTemplate的使用标准用法没返回值用法异常处理案例
事务的基本概念
什么是事务
是逻辑上一组操作,组成这组操作各个单元要么一起成功要么一起失败。
事务的特性
原子性 :不可分割性一致性 :事务执行前后,数据完整性保持一致。隔离性 :一个事务执行的时候,不应该受到其他事务的干扰。持久性 :事务一旦结束,数据就持久化到数据库。事务的隔离性不完善引发的问题
读问题 脏读 :一个事务读到另一个事务未提交的数据。不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致多次查询结果内容不一致。幻影读 :一个事务读到另一个事务已经提交的insert、delete的数据,导致多次查询结果集合不一致。写问题 丢失更新设置隔离级别解决读问题
read uncommitted
:读未提交,三个读问题都有。read committed
:读已提交,解决脏读,但是不可重复读和幻影读有可能发生。repeatable read
:可重复读,解决脏读和不可重复读,但是幻影读有可能发生。serializable
:可串行化,解决所有读问题。Spring的事务管理
在Spring中,由事务定义类TransactionDefinition
完成事务信息的定义,由事务管理器PlatformTransactionManager
根据事务定义信息进行事务的管理,在管理过程中生成事务的各种状态,将状态记录到事务状态对象TransactionStatus
中。
Spring事务管理的API

PlatformTransactionManager :平台事务管理器,真正进行事务管理的对象。 DataSourceTransactionManager :底层使用JDBC的模板HibernateTransactionManager :底层使用HibernateJpaTransactionManager平台事务管理器接口有三个方法:
方法名 | 方法定义 | 注释 |
commit | void commit(TransactionStatus status) | 根据事务状态提交事务 |
rollback | void rollback(TransactionStatus status) | 根据事务状态回滚事务 |
getTransaction | TransactionStatus getTransaction(TransactionDefinition definition) | 通过事务定义获取事务状态 |
TransactionDefinition :事务的定义信息
定义事务隔离级别 ISOLATION_DEFAULT :根据数据库默认隔离级别设置数据库隔离级别。(默认)ISOLATION_READ_UNCOMMITTED :读未提交ISOLATION_READ_COMMITTED :读已提交ISOLATION_REPEATABLE_READ :可重复读ISOLATION_SERIALIZABLE :可串行化定义事务传播行为 PROPAGATION_REQUIREDPROPAGATION_SUPPORTSPROPAGATION_MANDATORYPROPAGATION_REQUIRES_NEWPROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVERPROPAGATION_NESTED定义事务超时信息
TIMEOUT_DEFAULT:使用事务默认超时时间。通过以下方法可以获取事务定义信息
getIsolationLevel():获取事务隔离级别getName():获取事务名称getPropagationBehavior():获取事务传播行为getTimeout():获取事务超时时间isReadOnly():事务是否只读TransactionStatus :事务的状态
isNewTransaction():是否是新事务hasSavepoint():事务是否有保存点isCompleted():事务是否已经完成isRollbackOnly():事务是否是只能回滚setRollbackOnly():设置事务为只能回滚Spring的事务传播行为
事务的传播行为主要解决在复杂业务下的事务嵌套问题,比如说业务层之乐方法的相互调用。

事务传播行为取值
使用当前事务
PROPAGATION_REQUIRED
:默认值。如果A中有事务,使用A中的事务。如果A中没有事务,创建一个新的事务将A的内容包含进来。PROPAGATION_SUPPORTS
:如果A中有事务,使用A中的事务,如果A中没有事务,不使用事务。PROPAGATION_MANDATORY
:如果A中有事务,使用A中的事务,如果A中没有事务,抛异常。不使用当前事务
PROPAGATION_REQUIRES_NEW
:如果A中有事务,将A中的挂起,创建一个新的事务执行自身部分。如果A中没有事务,创建一个新事务,执行自身部分。PROPAGATION_NOT_SUPPORTED
:如果A中有事务,将A中事务挂起。以非事务的方式运行。PROPAGATION_NEVER
:如果A中有事务,就抛异常。使用嵌套事务
PROPAGATION_NESTED
:当A执行结束后,会设置一个保存点。如果B的部分没有错误,执行通过,如果B的部分出错,允许回滚到最初始也可以回滚到保存点。Spring的事务管理案例环境搭建
Spring的事务管理的分类
编程式事务管理:手动编写代码完成事务管理声明式事务管理:通过配置方式完成事务管理 XML方式注解方式创建相关接口和类并配置注解
package com.pc.service;/** * 账号服务接口 * * @author Switch * @data 2016年11月25日 * @version V1.0 */public interface AccountService { /** * 转账 * @param from 转账者 * @param to 收账者 * @param money 钱数 */ public void transfer(String from, String to, Double money);}package com.pc.service.impl;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.pc.dao.AccountDao;import com.pc.service.AccountService;/** * 账号服务接口实现类 * @author Switch * @data 2016年11月25日 * @version V1.0 */// 配置服务层注解@Service("accountService")public class AccountServiceImpl implements AccountService { /** * 注入账号持久层对象依赖 */ @Resource(name = "accountDao") private AccountDao accountDao; @Override public void transfer(String from, String to, Double money) { accountDao.transferFrom(from, money); // int i = 1 / 0; accountDao.transferTo(to, money); }}package com.pc.dao;/** * 账号持久层接口 * * @author Switch * @data 2016年11月25日 * @version V1.0 */public interface AccountDao { /** * 从哪个账户转账 * @param from 转账者 * @param money 钱数 */ void transferFrom(String from, Double money); /** * 转账到哪个账户 * @param to 收账者 * @param money 钱数 */ void transferTo(String to, Double money);}package com.pc.dao.impl;import org.springframework.jdbc.core.support.JdbcDaoSupport;import com.pc.dao.AccountDao;/** * 账号持久层接口实行类 * * @author Switch * @data 2016年11月25日 * @version V1.0 */// 配置持久层组件注解public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void transferFrom(String from, Double money) { } @Override public void transferTo(String to, Double money) { }}配置Spring
<?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: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"> <!-- 配置组件扫描 --> <context:component-scan base-package="com.pc.service.impl"/> <!-- 配置账号dao,并注入数据源 --> <bean id="accountDao" class="com.pc.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- spring配置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> <!-- 引入外部属性文件 --> <context:property-placeholder location="classpath:db.properties"/></beans>在DAO中使用JDBC的模板
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void transferFrom(String from, Double money) { super.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from); } @Override public void transferTo(String to, Double money) { super.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to); }}编写测试类
package com.pc.test;import javax.annotation.Resource;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.pc.service.AccountService;/** * 测试事务 * * @author Switch * @data 2016年11月25日 * @version V1.0 */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class TestTX { @Resource(name = "accountService") AccountService accountService; @Test public void test1() { accountService.transfer("Switch", "Kity", 1000d); }}Spring的声明式事务管理
声明式的事务底层都是基于AOP的。
一般开发种常用的是XML方式的声明式事务,但有时候为了简单也会使用注解方式的事务。
引入jar包 
XML方式的声明式事务
配置事务管理器
<!-- 配置事务管理器 --><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /></bean>配置一个事务通知
<!-- 基于XML的事务配置 --><!-- 配置事务通知 --><tx:advice id="txAdvice"> <tx:attributes> <!-- 配置事务定义 --> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED"/> </tx:attributes></tx:advice>配置AOP
<!-- 事务aop配置 --><aop:config> <aop:pointcut expression="execution(* com.pc.service.impl.AccountServiceImpl.transfer(..))" id="pointcut1"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/></aop:config>tx:method的配置
name:配置的方法名称,支持*通配符匹配propagation:事务传播行为isolation:事务隔离级别timeout:超时时间read-only:是否只读事务rollback-for:触发回滚的异常,逗号分隔no-rollback-for:不触发回滚的异常,逗号分隔注解方式的声明式事务
配置事务管理器
<!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /></bean>开启注解事务
<!-- 开启注解事务 --><tx:annotation-driven transaction-manager="transactionManager"/>在业务层添加一个事务的注解
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)public class AccountServiceImpl implements AccountService { ......}PS:事务的注解加在类上表示该类所有方法都被事务管理器管理,加在方法上,则只有该方法被事务管理器管理。
@Transactional的配置
value:使用的TransactionManagerpropagation:事务传播行为isolation:事务隔离级别timeout:超时readOnly:是否只读事务rollbackFor:触发回滚的异常类对象数组rollbackForClassName:出发回滚的异常类名称数组noRollbackFor:不触发回滚的异常类对象数组noRollbackForClassName:不触发回滚的异常类名称数组Spring的编程式事务管理
编程式事务基本不用,这里只是基本介绍
配置事务管理器
<!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /></bean>配置事务管理的模板(简化事务开发)
<!-- 配置事务管理模板 --><bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"/></bean>在业务层注入事务管理的模板
@Resource(name = "transactionTemplate")private TransactionTemplate transactionTemplate;进行事务管理
package com.pc.service.impl;import javax.annotation.Resource;import org.springframework.stereotype.Service;import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.annotation.Isolation;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;import org.springframework.transaction.support.TransactionCallbackWithoutResult;import org.springframework.transaction.support.TransactionTemplate;import com.pc.dao.AccountDao;import com.pc.service.AccountService;/** * 账号服务接口实现类 * @author Switch * @data 2016年11月25日 * @version V1.0 */// 配置服务层注解@Service("accountService")// @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)public class AccountServiceImpl implements AccountService { /** * 注入账号持久层对象依赖 */ @Resource(name = "accountDao") private AccountDao accountDao; @Resource(name = "transactionTemplate") private TransactionTemplate transactionTemplate; @Override public void transfer(final String from, final String to, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { accountDao.transferFrom(from, money); int i = 1 / 0; accountDao.transferTo(to, money); } }); }}TransactionTemplate的使用
标准用法
public Object transfer(final String from, final String to, final Double money) { return transactionTemplate.execute(new TransactionCallback() { @Override public Object doInTransaction(TransactionStatus arg0) { accountDao.transferFrom(from, money); int i = 1 / 0; accountDao.transferTo(to, money); return accountDao.toString(); } });}没返回值用法
@Overridepublic void transfer(final String from, final String to, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { accountDao.transferFrom(from, money); // int i = 1 / 0; accountDao.transferTo(to, money); } });}异常处理
public void transfer(final String from, final String to, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { try { accountDao.transferFrom(from, money); // int i = 1 / 0; accountDao.transferTo(to, money); } catch (Exception e) { e.printStackTrace(); } } });}案例
GitHub:SpringDataTest GitHub:MyStore-netease