Java 的事务详解

本文深入探讨了Java事务的ACID特性,并详细介绍了Spring框架中事务的实现,包括TransactionDefinition、PlatformTransactionManager和TransactionStatus的使用。通过代码示例和注解方式展示了如何在Spring中管理事务,特别提到了事务的传播行为和隔离级别选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 背景知识

事务,其实就是一个或者一组不会中途失败的操作。简单理解就是,要么同时成功,要么同时失败。一开始我对这句话有点不解,因为这句话有点故意押韵的意思,但是结合一个实际场景,就豁然开朗了。在网购的时候都需要通过网络支付才能完成下单,如果“付钱”这个动作没有完成,就显示“已支付”,那么就没有人会去网上卖东西。

 

  1. 事务的特性

根据上边的背景,我们可以总结出来事务的四个特性,也是面试中经常被问到的“ACID”。

 

  • A - atomcity 原子性:这个特性很容易理解,就是每一个事务都只有一种状态,要么成功,要么失败。
  • C - Consistency 一致性:在事务完成之后,所有的状态都是一直的,也就是调用链上的方法,都是成功的,只要有一个失败,那么都不是事务。
  • I - isolation 隔离性:事务与事务之间是独立的,不会相互影响。如果两个事务之间的操作有冲入,那么就必须是一个完成之后才会进行下一个。
  • D - durability 持久性:这个特性也很好理解,可以持久的。也就是事务一旦发生之后,一切更改都是持久的影响。

 

  1. spring 中的事务实现

Java中最常用的实现事务的方式就是利用Spring 本身的事务。

众所周知,作为Java中最主要的一个框架——Spring本身的功能是非常完善的,虽然已经有点臃肿,利用Spring进行事务的管理是一种非常高效的方法。

这里先贴出一张网络上常见的图:

​​

​​

从这张图中我们可以看到三个非常重要的类:TransactionDefinition、PlatformTransactionManager以及TransactionStatus。下边是对他们的详解。

 

3.1 TransactionDefinition

这个是用来定义事务的传播行为的类,可以配置的项有下边6种。

 

  • PROPAGATION_MANDATORY - 强制事务,没有事务就会报错
  • PROPAGATION_NESTED - 嵌套事务,如果有事务,就会嵌套当前事务;如果没有,则会新增一个事务。
  • PROPAGATION_NEVER - 永远不使用事务。
  • PROPAGATION_NOT_SUPPORTED - 不使用事务,如果当前有事务,会被挂起(不生效)。
  • PROPAGATION_REQUIRED - 最常见的操作,会用事务执行,如果没有事务,就会新建一个事务。
  • PROPAGATION_REQUIRES_NEW - 每次都会新建事务
  • PROPAGATION_SUPPORTS - 如果有事务,就会使用事务,如果没有,就会以非事务的形式执行。

 

上边的事务的传播行为,使用最多的是:PROPAGATION_REQUIRED ,也可以根据自己的实际使用情况使用其他的类型。

 

3.2 PlatformTransactionManager

这个是Spring 中的事务管理器,里边有三个方法:

 

  • getTransaction - 根据上边的定义获取事务
  • commit - 提交事务
  • rollback - 回滚事务

 

可以看出这个是事务的基本使用方法。

3.3 TransactionStatus

故名思意,这个类是用来表示事务的各个状态的,这个接口有下边的方法:

 

  • flush - 刷新所有的数据,但是这个主要是取决于底层的JPA或者Hibernate的机制。
  • hasSavepoint - 检查是否有存档点,存档点是回滚事务的地方。
  • isCompleted - 检查事务是否完成提交/回滚。
  • isNewTransaction - 检查当前事务是否是新的事务。
  • isRollbackOnly - 检查当前事务是否为“只回滚”状态。
  • setRollbackOnly - 将事务设置成“只回滚”状态,被设置的线程只要出现异常就会回滚。

 

4.spring中事务的使用

4.1 代码实现

前边铺垫这么久,其实事务的使用非常简单,实际的代码如下:

DefaultTransactionDefinition def = new DefaultTransactionDefinition();

def.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);

TransactionStatus status = transactionManager.getTransaction(def);

try {

    // 自己的逻辑

    } catch (Exception ex) {

    LOG.error("Exception in executeSelect:",ex);

    transactionManager.rollback(status);

    throw ex;

}

transactionManager.commit(status);

 

 

这里的使用的流程就是:

 

  1. 定义一种事务的传播行为,当然这个事务的传播行为是可以共用的;
  2. 获取当前事务的状态,也就是上边的status;
  3. 进行自己的逻辑,一般会用try catch处理异常;
  4. 如果出现异常,就在catch中进行回滚;如果没有出现异常,就提交事务。

 

4.2 注解实现

虽然上边的代码比较简单,而且容易上手,但是更加常用的还是利用注解来标记事务。用注解来表示事务,其实只是需要在自己的业务代码中增加@Transactional 注解。

这个注解的常用配置属性有两个:isolation和propagation。

 

isolation是指事务的隔离级别,Spring 中,事务的隔离级别有五种:

 

  • ISOLATION_DEFAULT - 默认事务(个人觉得只是占位符)
  • ISOLATION_READ_COMMITTED - 读已提交
  • ISOLATION_READ_UNCOMMITTED - 读未提交
  • ISOLATION_REPEATABLE_READ - 可以重复读
  • ISOLATION_SERIALIZABLE - 同步读取

 

这几种隔离级别中,一般只会用第二种,其他的除了最后一种,都会有不同的安全隐患,所以一般不会用。而最后一种,虽然是最安全的,但是其速度非常慢,所以也是比较少使用。

 

propagation属性对应的是上边的事务的传播行为,这里使用PROPAGATION_REQUIRED即可。综上,要实现和4.1一样的效果,只要用下边这行注释即可。

 

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值