Spring 事务管理
事务
概念 事务:指的是逻辑上的一组操作,组成这个事务的各个执行单元,要么一起成功,要么一起失败!
事务的特性
安全性问题 如果不考虑隔离性,引发安全性问题
如何解决安全性问题
读问题解决,设置数据库隔离级别
写问题解决可以使用 悲观锁
和 乐观锁
的方式解决
Spring 框架的事务管理
Spring 框架的事务管理相关的类和 API 接口
PlatformTransactionManager
接口————平台事务管理器。(真正管理事务的类)。该接口有具体的实现类,根据不同的持久层框架,需要选择不同的实现类!
TransactionDefinition
接口————事务定义信息。(事务的隔离级别,传播行为,超时,只读)
TransactionStatus
接口————事务的状态
总结:上述对象之间的关系:平台事务管理器真正管理事务对象。根据事务定义的信息 TransactionDefinition
进行事务管理,在管理事务中产生一些状态,将状态记录到 TransactionStatus
中。
接口的实现类
如果使用的 Spring 的 JDBC
模板或者 MyBatis
框架,需要选择 DataSourceTransactionManager
实现类 如果使用的是 Hibernate
的框架,需要选择 HibernateTransactionManager
实现类
该接口的常用方法
void commit(TransactionStatus status)
TransactionStatus getTransaction(TransactionDefinition definition)
void rollback(TransactionStatus status)
TransactionDefinition 接口中实现类和常用的方法
事务隔离级别的常量
static int ISOLATION_DEFAULT————采用数据库的默认隔离级别 static int ISOLATION_READ_UNCOMMITTED static int ISOLATION_READ_COMMITTED static int ISOLATION_REPEATABLE_READ static int ISOLATION_SERIALIZABLE
事务的传播行为常量(不用设置,使用默认值
)
事务的传播行为:解决的是业务层之间的方法调用!
PROPAGATION_REQUIRED(默认值)————A 中有事务,使用 A 中的事务。如果没有,B 就会开启一个新的事务,将 A 包含进来。(保证 A,B 在同一个事务中),默认值! PROPAGATION_SUPPORTS————A 中有事务,使用 A 中的事务。如果 A 中没有事务,那么 B 也不使用事务。 PROPAGATION_MANDATORY————A 中有事务,使用 A 中的事务。如果 A 没有事务,抛出异常。
PROPAGATION_REQUIRES_NEW(记)————A 中有事务,将 A 中的事务挂起。B 创建一个新的事务。(保证 A,B 没有在一个事务中) PROPAGATION_NOT_SUPPORTED————A 中有事务,将 A 中的事务挂起。 PROPAGATION_NEVER————A 中有事务,抛出异常。
PROPAGATION_NESTED(记)————嵌套事务。当 A 执行之后,就会在这个位置设置一个保存点。如果 B 没有问题,执行通过。如果 B 出现异常了,运行客户根据需求回滚(选择回滚到保存点或者是最初始状态)
搭建事务管理转账案例的环境 (强调:简化开发,以后 DAO
可以继承 JdbcDaoSupport
类)
步骤一:创建 WEB 工程,引入需要的 jar 包
IoC 的 6 个包 AOP 的 4 个包 C3P0 的 1 个包 MySQL 的驱动包 JDBC 模板 2 个包 整合 JUnit 测试包
步骤二:引入配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <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" ></beans >
步骤三:创建对应的包结构和类
com.itheima.demo2
AccountService AccountServlceImpl AccountDao AccountDaoImpl
步骤四:引入 Spring 的配置文件,将类配置到 Spring 中 1 2 3 4 5 <bean id ="accountService" class ="com.renkaigis.demo2.AccountServiceImpl" > </bean > <bean id ="accountDao" class ="com.renkaigis.demo2.AccountDaoImpl" > </bean >
步骤五:在业务层注入 DAO ,在 DAO 中注入 JDBC 模板 (强调:简化开发,DAO 可以继承 JdbcDaoSupport
类)
1 2 3 4 5 6 7 <bean id ="accountService" class ="com.renkaigis.demo2.AccountServiceImpl" > <property name ="accountDao" ref ="accountDao" /> </bean > <bean id ="accountDao" class ="com.renkaigis.demo2.AccountDaoImpl" > <property name ="dataSource" ref ="dataSource" /> </bean >
步骤六:编写 DAO 和 Service 中的方法 Service
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class AccountServiceImpl implements AccountService { @Resource(name = "accountDao") private AccountDao accountDao; public void setAccountDao (AccountDao accountDao) { this .accountDao = accountDao; } @Override public void pay (String out, String in, double money) { accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }
DAO
:
1 2 3 4 5 6 7 8 9 10 11 12 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void outMoney (String out, double money) { this .getJdbcTemplate().update("update t_account set money = money - ? where name = ?" , money, out); } @Override public void inMoney (String in, double money) { this .getJdbcTemplate().update("update t_account set money = money + ? where name = ?" , money, in); } }
步骤七:编写测试程序 1 2 3 4 5 6 7 8 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Demo1 { @Resource(name = "accountService") private AccountService accountService; @Test public void run1 () { accountService.pay("小关" , "小西" , 1000 ); } }
Spring 框架事务管理的分类
Spring 的编程式事务管理(不推荐使用)
通过手动编写代码的方式完成事务的管理(不推荐)
Spring 的声明式事务管理
(底层采用 AOP
的技术)
通过一段配置的方式完成事务的管理(重点掌握注解
的方式)
Spring 框架事务管理之编程式事务管理(了解) 说明:Spring 为了简化事务管理的代码:提供了模板类 TransactionTemplate
,所以手动编程的方式来管理事务,只需要使用该模板类即可!
步骤一:配置一个事务管理器 Spring 使用 PlatformTransactionManager
接口来管理事务,所以需要使用到他的实现类!
1 2 3 4 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean >
步骤二:配置事务管理的模板 1 2 3 4 <bean id ="transactionTemplate" class ="org.springframework.transaction.support.TransactionTemplate" > <property name ="transactionManager" ref ="transactionManager" /> </bean >
步骤三:在需要进行事务管理的类中,注入事务管理的模板 1 2 3 4 <bean id ="accountService" class ="com.renkaigis.demo2.AccountServiceImpl" > <property name ="accountDao" ref ="accountDao" /> <property name ="transactionTemplate" ref ="transactionTemplate" /> </bean >
步骤四:在业务层使用模板管理事务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao (AccountDao accountDao) { this .accountDao = accountDao; } private TransactionTemplate transactionTemplate; public void setTransactionTemplate (TransactionTemplate transactionTemplate) { this .transactionTemplate = transactionTemplate; } @Override public void pay (String out, String in, double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult () { @Override protected void doInTransactionWithoutResult (TransactionStatus transactionStatus) { accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }); } }
Spring 框架事务管理之声明式事务管理 即通过配置文件来完成事务管理(AOP 思想)
声明式事务管理又分成两种方式
基于 AspectJ 的 XML 方式(重点掌握) 基于 AspectJ 的注解方式(重点掌握)
Spring 框架事务管理之基于 AspectJ 的 XML 方式(重点掌握) 步骤一:恢复转账开发环境 步骤二:引入 AOP 的开发包 步骤三:配置事务管理器 1 2 3 4 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean >
步骤四:配置事务增强 1 2 3 4 5 6 7 <tx:advice id ="myAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="pay" propagation ="REQUIRED" /> </tx:attributes > </tx:advice >
name
:绑定事务的方法名,可以使用通配符,可以配置多个。propagation
:传播行为isolation
:隔离级别read-only
:是否只读timeout
:超时信息rollback-for
:发生哪些异常回滚no-rollback-for
:发生哪些异常不回滚
步骤五:配置 AOP 的切面 1 2 3 4 <aop:config > <aop:advisor advice-ref ="myAdvice" pointcut ="execution(public * com.renkaigis.demo3.AccountServiceImpl.pay(..))" /> </aop:config >
注意 :如果是自己编写的切面,使用 <aop:aspect>
标签,如果是系统提供的,使用 <aop:advisor>
标签。
步骤六:编写测试类 1 2 3 4 5 6 7 8 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Demo2 { @Resource(name = "accountService") private AccountService accountService; @Test public void run1 () { accountService.pay("小关" , "小西" , 1000 ); } }
Spring 框架事务管理之基于 AspectJ 的注解方式 (重点掌握,最简单的方式)
步骤一:恢复转账的开发环境 步骤二:配置事务管理器 同上。
步骤三:开启注解事务 1 2 <tx:annotation-driven transaction-manager ="transactionManager" />
步骤四:在业务层上添加一个注解:@Transactional 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Transactional public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao (AccountDao accountDao) { this .accountDao = accountDao; } @Override public void pay (String out, String in, double money) { accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }
步骤五:编写测试类 1 2 3 4 5 6 7 8 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext3.xml") public class Demo2 { @Resource(name = "accountService") private AccountService accountService; @Test public void run1 () { accountService.pay("小关" , "小西" , 1000 ); } }