Spring:本地事务和事务失效

事务的基本性质

数据库事务的几个特性:A(原子性)C(一致性)I(隔离性)D(持久性),即ACID原则

事务的隔离级别

从1-4,数字越大,并发能力越低

1、读未提交

该隔离级别下的事务会读到其他未提交事务的数据,此现象也成为脏读;

2、读已提交

一个事务可以读取另一个已提交的事务,多次读会造成不一样的结果,此现象称为不可重复读问题;Oracle和SQL Server的默认隔离级别

3、可重复读

是MySQL默认的隔离级别,在同一个事务里,只要未结束,读到的都是一致的,就算外面把数据删了,还是一致的;但是,会有幻读现象;MySQL的InnoDB引擎是通过next-key locks机制来避免幻读的;

4、序列化

在该隔离级别下,事物都是串行执行的,几乎没有任何并发能力了;MySQL数据库的InnoDB引擎会给读操作隐式加一把共享锁,从而避免脏读、不可重复读和幻读问题;

在spring中设置

@Transactional(isolation = Isolation.DEFAULT)

所有的隔离级别

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);
    private final int value;
    private Isolation(int value) {
        this.value = value;
    }
    public int value() {
        return this.value;
    }
}

事务的传播行为

  • REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
  • REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

在spring中设置

@Transactional(propagation = Propagation.REQUIRED )

所有传播行为

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;
    private Propagation(int value) {
        this.value = value;
    }
    public int value() {
        return this.value;
    }
}

一个小坑:本地事务失效问题

同一对象内事务方法互调默认失效,原因:绕过了代理对象,相当于代码复制粘贴;

因为事务底层基于AOP实现,所以事务机制只对代理对象起作用,而对普通对象不会起作用;

1、Spring事务底层是怎么工作的?

切面逻辑,在事务管理器里面创建数据库连接,避免每条语句创建数据库连接,这样的话这多条语句就不是在一个事务里面了;之后会把自动提交设置为false,conn.autocommit=false;在后面进行提交或回滚,conn.commit(),conn.rollback();

2、同类方法调用为什么会事务失效?

相当于是普通对象,即UserService同类方法调用a()方法,就相当于new UserService().a();这是一个普通对象,不是代理对象,直接忽视了事务注解,因为只有UserService的代理对象才会管你的事务注解;

3、解决方案:使用代理对象来调用事务方法

(1)引入aop-starter:引入了aspectj;

(2)@EnableAspectJAutoProxy(exposeProxy=true):开启aspectj动态代理功能,以后所有的动态代理都是aspectj帮我们创建的,即使没有接口也可以;exposeProxy=true对外暴露代理对象

(3)本类互调调用对象

public void a(){
    OrderServiceImpl orderService = (OrderServiceImpl)AopContext.currentProxy();
    orderService.b();
    orderService.c();
}

本文完!!!希望能对你有所帮助!!!

你可能感兴趣的:(SpringBoot笔记,spring,java)