事务、事务隔离级别、Spring事务配置、Spring事务的传播特性

本文详细介绍了数据库事务的四大特性(ACID),包括原子性、一致性、隔离性和持久性,并探讨了四种事务隔离级别及其可能导致的问题。接着,讲解了Spring的事务管理,包括编程式和声明式事务,并强调了@Transactional注解的使用和事务传播特性。最后,通过示例解释了事务传播在实际应用中的场景。
摘要由CSDN通过智能技术生成

什么是事务

事务的概念

事务:是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向 系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元);

通俗点说就是:一组sql语句组成的数据库逻辑处理单元,在这组的sql操作中,要么全部执行成功,要么全部执行失败。

最常见的例子就转账:

小明给如花转账:

开启事务 ------
1.从小明的账户扣除1000块
2.给如花的账户增加1000块
事务提交------

上面例子的任何步骤一旦出现问题,都会导致事务回滚。
从搭讪到结婚就是事务提交。 女方要求男方重新追求她一次就是事务回滚🤣。

事务的四大特性(ACID)

  • 原子性 (Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
  • 一致性(Consistency):一致性是指执行事务前后的状态要一致,可以理解为数据一致性。如转账业务,无论事务执行 成功与否,参与转账的两个账号余额之和应该是不变的。
  • 隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相 互干扰。这个与事务设置的隔离级别有密切的关系。
  • 持久性 (Durability): 一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中。

原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终的目的。

事务的隔离级别

数据库事务的隔离级别有4种,由低到高分别为读未提交(READ UNCOMMITTED)读提交 (READ COMMITTED)可重复读 (REPEATABLE READ)串行化(SERIALIZABLE)。 而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。

脏读:(读取了未提交的新事务,然后被回滚了)
事务A读取了事务B中尚未提交的数据。如果事务B回滚,则A读取使用了错误的数据。

不可重复读:(读取了提交的新事务,指更新操作)
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

幻读:(也是读取了提交的新事务,指增删操作)
在事务A多次读取中,事务B对数据进行了新增操作,导致事务A多次读取的数据不一致。

不可重复读,针对的是行数据被修改,避免的方法就是行锁,而幻读是针对增加或删除行数据,避免的方法是表锁,带来的开销代价不一样。

读未提交(READ UNCOMMITTED)
读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。 会产生脏读。

读提交 (READ COMMITTED)
读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。 会产生不可重复读。

可重复读 (REPEATABLE READ)
重复读,就是在开始读取数据(事务开启)时,不再允许修改操作。可能会产生幻读。

串行化(SERIALIZABLE)
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但 是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

大多数数据库默认的事务隔离级别是Read committed, 比如Sql Server, Oracle。

Mysql的默认隔离级别是Repeatable read。

Spring事务配置

Spring支持编程式事务管理和声明式事务管理两种方式。

  • 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,Spring推荐使用TransactionTemplate。
  • 声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

@Override
@Transactional(rollbackFor = Exception.class)
public int delete(Long id) {

  // do something

}

默认配置下 Spring 只会回滚运行时、未检查异常(继承自 RuntimeException 的异常)或者 Error。
如果想回滚所有异常 加上rollbackFor = Exception.class 即可。

@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,@Transactional 注解将失效,也不会抛出任何异常。

同一个类中方法调用,导致@Transactional失效
接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。
其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

Spring事务的传播特性

什么是事务的传播特性?

指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。

代码举例

// ServiceA
@Service
public class ServiceA {

	@Autowired
	private ServiceB serviceB;
	
	@Transactional
    public void methodA() {
        System.out.println("methodA 执行了...");
        serviceB.methodB();
    }
}

// ServiceB
@Service
public class ServiceB {
    @Transactional
    public void methodB() {
        System.out.println("methodB 执行了...");
    }
}

Spring总共给出了7种事务传播行为:

在这里插入图片描述

关于事务挂起的举例:(某事务挂起之后,任何操作都不在该事务的控制之下)
例如: 方法A支持事务,方法B不支持事务。 即PROPAGATION_NOT_SUPPORTED

方法A调用方法B。
在方法A开始运行时,系统为它建立Transaction,方法A中对于数据库的处理操作,会在该Transaction的控制之下。
这时,方法A调用方法B,方法A打开的 Transaction将挂起,方法B中任何数据库操作,都不在该Transaction的管理之下。
当方法B返回,方法A继续运行,之前的Transaction恢复,后面的数据库操作继续在该Transaction的控制之下 提交或回滚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值