Spring事务详解

Spring事务详解

什么是事务?事务是逻辑上的一组操作,要么都执行,要么都不执行。

事务的特性

ACID,是指在写入数据库数据时,为了保证事务是正确可靠的,必须具备以下四个特性:

  • 原子性(Atomicity):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
  • 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
  • 事务隔离(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

Spring 中的事务

为了更好的管理事务相关的资源,Spring为我们提供了事务管理器,也就是PlatformTransactionManager

事务管理器介绍

Spring 框架中,事务管理有三个重要的接口:

  • **PlatformTransactionManager**: 事务管理器,Spring 事务策略的核心。
  • **TransactionDefinition**: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。
  • **TransactionStatus**: 事务运行状态。

PlatformTransactionManager 接口的具体实现如下:

由于Spring不直接管理事务,而是提供了事务管理器的接口的抽象类,而不同的平台会提供具体实现,比如:JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都实现了事务管理器。

如何使用事务管理器

Spring 提供了两种事务管理方式:

编程式事务

使用PlatformTransactionManager进行编程式事务管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class TransactionManagerService {
@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction(){
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
//TODO
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
transactionManager.rollback(status);
}
}
}

使用TransactionTemplate进行编程式事务管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class TransactionTemplateService {
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
//TODO
} catch (Exception e) {
transactionStatus.setRollbackOnly();
}
}
});
}
}

声明式事务

使用 @Transactional注解进行事务管理:

1
2
3
4
5
6
7
@Service
public class TransactionalService {
@Transactional(rollbackFor = Exception.class)
public void testTransaction(){
//TODO
}
}

事务属性详解

事务传播行为

事务传播传播行为是为了解决业务层方法之间相互调用的事务问题;当事务方法被另一个方法调用时必须指定事务是如何传播的。

Spring 事务有七种传播行为:

  • PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务,就加入到这个事务中,这是默认的传播行为;
  • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,则以非事务的方式执行;
  • PROPAGATION_MANDATORY:使用当前事务,如果当前没有事务,就会抛出异常;
  • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,则把当前事务挂起;
  • PROPAGATION_NOT_SUPPORTED:以非事务的方式执行,如果当前存在事务,则把当前事务挂起;
  • PROPAGATION_NEVER:以非事务的方式执行,如果当前存在事务,就会抛出异常;
  • PROPAGATION_NESTED:如果当前存在事务,则创建一个子事务,如果当前没有事务,则创建一个新事务。

事务隔离级别

Spring 中的事务隔离级别其实也就是数据库中的四种数据隔离级别,每次访问数据库时,都会根据事务上定义的隔离级别来建立数据库连接。

Spring 事务管理器支持五种隔离级别:

  • ISOLATION_DEFAULT:使用数据库的隔离级别,MySQL 默认使用的是REPEATABLE_READ,Oracle 默认使用READ_COMMITTED
  • ISOLATION_READ_UNCOMMITTED:读未提交,是最低的隔离级别,可以读取尚未提交的变更数据,可能会导致脏读、幻读或者不可重复读;
  • ISOLATION_READ_COMMITTED:读已提交,允许读取已经提交的变更数据,可以方式脏读,但是还是会发生幻读或者不可重复读;
  • ISOLATION_REPEATABLE_READ:可重复读,对一个字段多次读取的结果都是一致的,除非数据被本身的事务修改,可以阻止脏读和不可重复读,但是幻读还是可能发生;
  • ISOLATION_SERIALIZABLE:序列化,最高的隔离级别,完全服从ACID特性,所有事务都不能并发执行,但是会严重影响性能,可以防止脏读、幻读和不可重复读。

事务超时时间

TIMEOUT_DEFAULT:事务允许执行的最长时间,如果超过时间限制,则事务自动回滚,单位是秒,默认值是-1,没有超时限制。

事务是否只读

readOnly:事务是否只读,对于只读取事务的查询事务,可以指定为只读事务,对于只读的事务,数据库会提供一些优化手段。

事务回滚策略

rollbackFor:定义了那些异常会导致事务回滚,默认情况下,事务只有遇到运行期异常(RuntimeException 的子类)时才会回滚,Error 也会导致事务回滚,但是,在遇到检查型(Checked)异常时不会回滚。

Transactional 注解

作用范围

  1. 方法 :推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效;
  2. :如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效;
  3. 接口 :不推荐在接口上使用。

常用的配置参数

Transactional 注解测参数和上面介绍的事务属性类似:

属性名 说明
propagation 事务的传播行为
isolation 事务的隔离级别
timeout 事务的超时时间
readOnly 指定事务是否为只读事务
rollbackFor 用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型

注意事项

  • 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;
  • 正确的设置 @TransactionalrollbackForpropagation 属性,否则事务可能会回滚失败;
  • @Transactional 注解的方法所在的类必须被 Spring 管理,否则不生效;
  • 底层使用的数据库必须支持事务机制,否则不生效。
作者

ero

发布于

2022-04-07

更新于

2022-06-11

许可协议

评论