Spring事务的问题总结

80 阅读3分钟

事务的隔离级别

Read uncommitted

Read committed

Repeatable read

Serializable

事物具有ACID的四个基本属性

原子性(Atomicity) 可用性(consistency) 隔离性(isolation) 持久性 (持久性)

常见的几事务类型

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

事务实现的几种方式

1.编程式事务(忽略) 2.声明式事务 着重讲解的是声明式事务 是建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中 声明式事务管理也有两种方式: 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用

事务回滚原则

事务只有在抛出异常为运行时异常时才会生效也就是RuntimeException的子类(Errors 也会导致事务回滚)而抛出checked异常则不会导致事务回滚、

事务是否生效

1.首先是mysql数据库中mylSAM引擎是不支持的事务的只有InnoDB是支持事务 2.JDK动态代理实现的Spring事务 这种方式除了实现自接口的非static方法,其他方法均无效。 3.cglib动态代理

4.自身调用问题 spring是通过aop的方式实现的事务管理,为每个需要事务管理的bean创建代理对象, 然后通过代理对象拦截了目标方法的执行,在方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。

@Service
public class TestService {
    public void service1(){
        this.service2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void service2(){
        //db操作
    }
}

因为this.service2()方法是不生效的 ,因为是通过This调用的,不是通过代理对象 this.service2();不会被拦截,所以事务是无效的,如果外币直接通过TestService这个Bean来调用service2方法,事务是有效的 在当前类中注入自己是有效的,简而言之必须通过代理对象调用的方法才会加入事务

@Service
public class TestService {
@Autowired
TestService testService
    public void service1(){
        testService.service2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void service2(){
        //db操作
    }
}

5.异常被捕获 当业务代码抛出异常,spring感知到异常的时候,才会进行回滚,如果在业务方法里面捕获了异常,spring无法感知到异常,就不会进行回滚

@Transactional(rollbackFor = Exception.class)
public void m2(){
    try{
        //db操作
    }catch (Exception e){
        logger.error("方法执行出现异常",e);
    }
}

6.业务和Spring事务代买必须在一个线程中 Spring事务中使用了ThreadLocal, ThreadLocal可以实现同一个线程中数据共享,必须是同一个线程的时候,数据才可以共享,这就要求业务代码必须和spring事务的源码执行过程必须在一个线程中,才会受spring事务的控制,比如下面代码,方法内部的子线程内部执行的事务操作将不受m1方法上spring事务的控制