Spring事务

208 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一. Spring事务分类

Spring 提供了两种事务管理方式:声明式事务管理和编程式事务管理。

1. 编程式事务

在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中显式调用 beginTransaction()、commit()、rollback() 等事务管理相关的方法,这就是编程式事务管理。
简单地说,编程式事务就是在代码中显式调用开启事务、提交事务、回滚事务的相关方法。

2. 声明式事务

Spring 的声明式事务管理是建立在 Spring AOP 机制之上的,其本质是对目标方法前后进行拦截,并在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。而Spring 声明式事务可以采用 基于 XML 配置 和 基于注解 两种方式实现
简单地说,声明式事务是编程式事务 + AOP 技术包装,使用注解进行扫包,指定范围进行事务管理。

二. 事务失效的原因

1. 数据库引擎不支持事务

以 MySQL 为例,其 MyISAM 引擎是不支持事务操作的,InnoDB 才是支持事务的引擎,一般要支持事务都会使用 InnoDB。 MySQL从5.5.5 开始的默认存储引擎是:InnoDB,之前默认的都是MyISAM。

2. 事务所在的类没有被Spring托管

3. 方法的标注修饰无效

Spring AOP对于接口-实现类这种方式是基于JDK动态代理的方式实现的,由于接口定义的方法是public的,java要求实现类所实现接口的方法必须是public的(不能是protected,private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其它方法不可能被动态代理,相应的也就不能实施AOP增强,也即不能进行Spring事务增强。

4. 方法自调用

如下面的代码,在update中调用updateOrder是无法使用事务的,事务不起作用其根本原因就是未通过代理调用,因为事务是在代理中处理的,没通过代理,也就不会有事务的处理。

@Service
public class OrderServiceImpl implements OrderService {
    public void update(Order order) {
        updateOrder(order);
    }
    @Transactional
    public void updateOrder(Order order) {
        // update order
    }
}

5. 数据源没有配置事务管理器

6. 设置了Propagation.NOT_SUPPORTED

7. 默认 checked 异常不回滚事务

Spring 默认只为 RuntimeException 异常回滚事务,如果方法往外抛出 checked exception,该方法虽然不会再执行后续操作,但仍会提交已执行的数据操作。

8.try-catch捕获了异常