[TOC]
前言 ​
学习目标 ​
- 理解Spring事务核心思想
- 熟悉Spring事务的注解@Transactional
前置知识准备 ​
- 事务
- AOP思想
事务的回顾 ​
事务的特性 ​
- 原子性 Atomicity
- 一致性 Consistency
- 隔离性 Isolation
- 持久性 Durability
事务并发引起的问题 ​
- 脏读
- 一个事务读取到另外一个事务的数据
- 不可重复读
- 一个事务读取到另外一个事务的数据
- 虚读/幻读
- 一个事务读取到另外一个事务的数据
数据库的隔离级别 ​
- 读未提交(Read uncommitted)
- 读已提交(Read committed)
- 可重复读(Repeatable read)
- 串行化(Serializable)
| 脏读 | 不可重复读 | 虚读/幻读 | |
|---|---|---|---|
| 读未提交 | × | × | × |
| 读已提交 | √ | × | × |
| 可重复读 | √ | √ | × |
| 串行化 | √ | √ | √ |
MySql的默认隔离级别是可重复读,但没有虚读问题的。
事务的核心接口 ​
- PlatformTransactionManager 平台事务管理器
- TransactionStatus 事务状态
- TransactionDefinition 事务定义
PlatformTransactionManager平台事务管理器 ​
平台事务管理器,Spring要管理事务,必须使用事务管理器 有多种实现,通过实现此接口,Spring可以管理任何实现了这些接口的事务。 开发人员可以使用统一的编程模型来控制管理事务。
常见的事务管理器的实现 DataSourceTransactionManager,jdbc开发时事务管理器,使用JdbcTemplate、MyBatis HibernateTransactionManager,Hibernate开发时事务管理器,整合Hibernate
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}TransactionStatus事务状态 ​
获取事务的状态(回滚点、是否完成、是否新事务、是否回滚)属性,是一个过程值
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
boolean hasSavepoint();
void flush();
}提供了关于事务状态的方法

TransactionDefinition事务定义 ​
定义事务的名称、隔离级别、传播行为、超时时间长短、只读属性等
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
default int getPropagationBehavior() {
return 0;
}
default int getIsolationLevel() {
return -1;
}
default int getTimeout() {
return -1;
}
default boolean isReadOnly() {
return false;
}
@Nullable
default String getName() {
return null;
}
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
}事务的传播行为 ​
事务的传播行为属于TransactionDefinition,这个概念是之前没有讲过的一个概念
指多个方法之间如何来共享事务
- REQUIRED
- 一荣俱荣
- REQUIRES_NEW
- 自私型
- NESTED
- 无私型
REQUIRED ​
如果当前没有事务,就新建一个事务; 如果当前存在,则加入进来,作为一个事务。
一荣俱荣,一损俱损。要么一起提交,要么一起回滚。
现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?REQUIRES_NEW ​
如果当前没有事务,新建事务; 如果当前存在事务,则新建一个事务。
自私型。外部不会影响内部,内部会影响外围。
现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?NESTED ​
如果当前没有事务,就新建一个事务; 如果当前存在事务,则以嵌套事务的方式运行。
无私型。外围会影响内部,内部不会影响外围。
现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?其他传播行为 ​
| 传播行为 | 描述 |
|---|---|
| PROPAGATION_SUPPORTS | 支持当前事务,假设当前没有事务,就以非事务方式运行 |
| PROPAGATION_MANDATORY | 支持当前事务,假设当前没有事务,就抛出异常 |
| PROPAGATION_NOT_SUPPORTED | 以非事务方式运行操作。假设当前存在事务,就把当前事务挂起 |
| PROPAGATION_NEVER | 以非事务方式运行,假设当前存在事务,则抛出异常 |
事务的案例 ​
不管使用的是哪一个案例,只要使用Spring事务,必然要使用Spring事务管理器。
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}TransactionTemplate ​
事务的模板,采用事务模板提供的方法来使用事务
在容器中注册TransactionTemplate组件
@Configuration
@ComponentScan("com.cskaoyan")
public class MyBatisConfiguration {
// javaConfig讲过这个组件注册
// MyBatis注册的组件略
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
TransactionTemplate transactionTemplate = new TransactionTemplate();
transactionTemplate.setTransactionManager(transactionManager);
return transactionTemplate;
}
}使用TransactionTemplate提供的方法
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
AccountDao accountDao;
@Autowired
TransactionTemplate transactionTemplate;
@Override
public void transfer(String from, String dest, Integer money) {
Integer fromMoney = accountDao.selectMoneyByName(from) - money;
Integer destMoney = accountDao.selectMoneyByName(dest) + money;
//execute方法的返回值 是doInTransaction方法的返回值
Integer execute = transactionTemplate.execute(new TransactionCallback<Integer>() {
//需要增加事务的代码放入到doInTransaction中
//如果需要增加事务的方法需要返回值 → 直接返回对应的值即可
@Override
public Integer doInTransaction(TransactionStatus transactionStatus) {
accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
int i = 1/0;
accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务
return null;
}
});
/*transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务
}
});*/
}
}Transactional注解 ​
@Transactional注解的ElementType为,意味着可以写在
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}使用注解前,需要
@Configuration
@ComponentScan("com.cskaoyan")
@EnableTransactionManagement
public class MyBatisConfiguration {}直接使用@Transactional注解,可以使用注解提供的属性
/**
* 在类上增加@Transactional 意味着该类下的所有方法都增加事务
* @Transactional要增加在容器中的组件或组件中的方法里
*/
@Transactional
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
AccountDao accountDao;
//对应的方法增加上事务
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = 5)
@Override
public void transfer(String from, String dest, Integer money) {
Integer fromMoney = accountDao.selectMoneyByName(from) - money;
Integer destMoney = accountDao.selectMoneyByName(dest) + money;
accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
int i = 1/0;
accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务
}
}笔记 ​
- spring-jdbc依赖。spring管理事务
- InitializingBean初始化生命周期
- 整合MyBatice框架是为了把框架需要的实例放到容器里管理起来
- 事务定义,超时时间5,说明5s后就不能提交了
- Requires_New,内部方法更重要,Nested外部方法更重要。比如register调用coupon,用nested,register失败则coupon也回滚,反之则coupon回滚,register不变。
- 管理事务实际上是在管理连接,连接在连接池