目录
Spring事务管理
首先澄清一个误点:Spring本身是没有事务一说的,数据库对事务的支持才是Spring事务的本质。
Spring事务分为两类:
- 声明式事务:
手动编写代码进行事务管理(很少使用) - 编程式事务
-
基于TransactionProxyFactoryBean的方式(很少使用)
需要为每个进行事务管理的类,配置一TransactionProxyFactoryBean进行增强
-
基于AspectJ的xml方式(经常使用)
一旦配置好,类上不需要添加任何东西
-
基于注解(经常使用)
配置简单,需要在业务层类上添加一个@Transactional的注解
-
事务特性及行为
事物是指一组逻辑上的操作,要么全部成功,不然全部失败。
特性
原子性( Atomicity )
事务中所有操作是不可再分割的原子单元。事务中所有操作要么都执行成功,要么都执行失败。
一致性( Consistency )
事务执行后,数据库状态与其他业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账户余额之和应该保持不变。
隔离性( Isolation )
隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会互相干扰。
持久性( Durability )
一旦事务提交成功,事务中所有的数据操作都必须被持久化保存到数据库中,即使提交事务后,数据库崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
传播行为
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。
Spring定义了七种传播行为:
1.PROPAGATION_REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB();
// do something
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// do something
单独调用methodB方法时,因为当前上下文不存在事务,所以会开启一个新的事务。
调用methodA方法时,因为当前上下文不存在事务,所以会开启一个新的事务。当执行到methodB时,methodB发现当前上下文有事务,因此就加入到当前事务中来。
2.PROPAGATION_SUPPORTS
如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB();
// do something
}
// 事务属性为SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
// do something
}
单纯的调用methodB时,methodB方法是非事务的执行的。当调用methdA时,methodB则加入了methodA的事务中,事务地执行。
3.PROPAGATION_MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB();
// do something
}
// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
// do something
}
当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);当调用methodA时,methodB则加入到methodA的事务中,事务地执行。
4.PROPAGATION_REQUIRES_NEW
使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作为事务管理器。
它会开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起。
5.PROPAGATION_NOT_SUPPORTED
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。
6.PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常。
7.PROPAGATION_NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB();
// do something
}
// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
// do something
}
隔离级别
基于元数据的 Spring 声明性事务 :
- Isolation 属性一共支持五种事务设置,具体介绍如下:
- DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别
- READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
- READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
- REPEATABLE_READ 会出幻读(锁定所读取的所有行)
- SERIALIZABLE 保证所有的情况不会发生(锁表)
名称 | 备注 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
DEFAULT | 使用数据库设置的隔离级别 ( 默认 ) | |||
READ_UNCOMMITTED | 隔离级别最低,并发性能高 | √ | √ | √ |
READ_COMMITTED | 锁定正在读取的行 | - | √ | √ |
REPEATABLE_READ | 锁定所读取的所有行 | - | - | √ |
SERIALIZABLE | 保证所有的情况不会发生(锁表) | - | - | - |
使用
采用纯注解方式-简便
- 启动类@EnableTransactionManagement开启事务
- 业务类、方法上均可以添加注解:
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
指定是否开启事务