2023-10-17 11:46

Spring中的事务管理

wanmatea

JavaEE

(525)

(0)

收藏

事务:

在Spring框架中,事务是指一组数据库操作(例如插入、更新、删除等)被视为一个不可分割的工作单元,要么全部执行成功,要么全部回滚,以确保数据的一致性和完整性。

Spring的事务管理能力是通过AOP(面向切面编程)和代理技术实现的。它提供了一个事务抽象层,使开发人员可以在应用程序中轻松地实现事务功能,而无需过多关注底层事务管理的细节。

Spring中的事务可用于将需要在事务范围内执行的一组数据库操作绑定到一个事务中。通过将这些操作纳入一个事务中,我们可以确保这些操作要么全部成功提交,要么全部回滚,以保持数据的一致性。

Spring框架提供了多种事务管理的策略,包括声明式事务管理和编程式事务管理。声明式事务管理可以通过@Transactional注解或XML配置来实现,可以将事务的定义与业务逻辑代码分离。而编程式事务管理则允许开发人员在代码中显式地控制事务的开始、提交和回滚。

通过Spring框架的事务管理特性,开发人员可以更加方便地管理和控制数据库操作的事务性,并确保数据的一致性和完整性。同时,Spring框架在事务管理方面还提供了灵活的配置选项,以适应不同的业务场景和需求。

事务的基本操作:

事务的基本操作通常包括以下几个步骤:

开启事务(Begin Transaction):事务的第一步是要开启一个事务,这样后续的所有数据库操作都可以在同一个事务中执行。在Spring中,可以使用@Transactional注解或编程式的方式来开启事务。

执行数据库操作:在事务范围内执行需要进行的数据库操作,包括插入、更新、删除等。这些操作将被纳入事务的管理之下,并在提交或回滚时一起操作。

提交事务(Commit):当所有的数据库操作成功执行并且不出现异常时,事务可以进行提交。提交时,所有的数据库操作将被正式应用到数据库中,使其生效。在Spring中,事务提交通常是由事务管理器自动完成的。

回滚事务(Rollback):如果在事务执行期间出现了异常或错误,事务可以选择回滚,即撤销之前的所有数据库操作。这样可以确保数据的一致性和完整性。在Spring中,可以通过捕获异常或进行手动回滚的方式来触发事务的回滚操作。

需要注意的是,事务的范围通常是由方法的边界决定的。即在开启事务前,进入方法执行,执行数据库操作,根据结果决定是提交还是回滚,然后结束事务。整个过程中,事务贯穿始终。

通过以上基本操作,可以实现数据库操作的原子性、一致性、隔离性和持久性(ACID 特性),以确保数据的正确性和可靠性。Spring框架提供了便捷的事务管理机制,使开发人员能够轻松地实现和控制事务的操作。

Spring中的事务应用场景:

如图所示是一个删除指定id部门的操作,而删除了指定id的部门,自然也要删除掉指定id部门的员员工,但是如果在删除完指定id的部门之后,服务器出错抛出了异常,中断了这个操作,那么此时就只删除了部门而没有删除对应部门的员工,这将会在数据库中留下异常的数据,因此我们就需要把这个操作捆绑成为一个事务:删除指定ID的部门和删除对应的员工必须同时执行。 

也就是说对串代码进行这种事务模式的修改:

而正如我们前面所介绍的,由于这些操作都是固定的,因此Spring为我们提供了一个注解@Transactional 

@Transactional:

@Transactional是Spring框架中用于声明式事务管理的注解。通过在方法或类级别上添加@Transactional注解,可以将方法或类纳入事务管理的范围中,使其具备事务特性。

使用@Transactional注解的好处是,它能够将事务的定义与业务逻辑代码分离,提供了一种声明式的方式来配置和管理事务。开发人员可以通过简单地在方法或类上添加@Transactional注解,而无需编写大量的事务管理代码。

@Transactional注解的常用属性:

propagation:指定事务的传播行为。它定义了在方法调用链中嵌套的情况下,事务是如何传播的。常见的传播行为包括REQUIRED(默认值)、REQUIRES_NEW、NESTED等。

isolation:指定事务的隔离级别。它决定了一个事务对于并发修改的数据可以见到多少。常见的隔离级别包括READ_COMMITTED(默认值)、READ_UNCOMMITTED、REPEATABLE_READ、SERIALIZABLE等。

timeout:指定事务的超时时间。如果事务在指定的超时时间内没有完成,将触发事务的回滚。单位为秒,默认值为-1,表示不设定超时。

readOnly:指定事务是否为只读事务。如果事务只涉及读取数据,并不会进行数据修改操作,可以将readOnly属性设置为true,以优化性能。

rollbackFor和noRollbackFor:用于指定特定的异常类型,当这些异常发生时,事务将回滚或不回滚。

除了以上属性,@Transactional注解还可以在XML配置中进行更细粒度的配置,包括指定基于方法名的事务策略、设置事务管理器、指定事务切面等。

总而言之,@Transactional注解提供了一种方便且简洁的方式来实现声明式事务管理。它使得开发人员可以更加专注于业务逻辑,而无需过多关注底层事务管理的细节。同时,通过灵活的属性配置,可以满足不同场景下的事务需求。

常见的事务隔离级别:

在Spring事务管理中,提供了几种事务隔离级别供选择:

READ_COMMITTED(已提交读):在READ_COMMITTED隔离级别下,事务只能读取到已经提交的数据。它可以避免脏读(Dirty Read),但是可能会发生不可重复读(Non-repeatable Read)和幻读(Phantom Read)。

READ_UNCOMMITTED(未提交读):在READ_UNCOMMITTED隔离级别下,事务可以读取到未提交的数据,可能会发生脏读,也就是读取到未提交的、其它事务正在修改的数据。这个隔离级别下,对数据的一致性要求最低。

REPEATABLE_READ(可重复读):在REPEATABLE_READ隔离级别下,事务在执行期间多次读取相同的数据时,保证能看到一致的数据快照。即使在事务期间有其他事务对数据进行了修改,也不会读到这些修改过的数据。但是,可能会发生幻读问题,即一个事务范围内,两次查询同一个条件返回的结果集不一致。为了避免幻读问题,需要使用锁机制或者更高级别的隔离级别。

SERIALIZABLE(串行化):在SERIALIZABLE隔离级别下,事务会按照串行执行的方式进行,每个事务只能看到其它事务已经提交的数据。它提供了最高的隔离级别,避免了脏读、不可重复读和幻读的问题,但是也会带来最高的并发度降低。

需要根据业务场景和需求选择合适的事务隔离级别。默认情况下,Spring事务将使用数据库的默认隔离级别(通常是READ_COMMITTED),可以通过@Transactional注解的isolation属性来显式指定隔离级别。

值得注意的是,不同的数据库可能对事务隔离级别的支持有所不同,特别是在分布式事务环境中,需要考虑数据库的兼容性和一致性要求。

代码示例:

回到我们之前的代码中:

我们此时手动的给这段代码的执行添加一个异常情况:除零算数异常

我们在前端尝试删除后,可以在控制台看到如下信息:

 这也就意味着我们成功的把这个方法变为了一个事务。

0条评论

点击登录参与评论