栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring事务

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring事务

文章目录
  • 数据库事务和spring事务的区别
  • Spring 事务管理接口介绍
    • PlatformTransactionManager :事务管理接口
    • TransactionDefinition:事务属性
    • TransactionStatus:事务状态
  • spring事物使用
  • 五大属性
  • 事务失效的7种情况
  • 如何快速定位事务相关bug?

数据库事务和spring事务的区别

二者本质上是同一个概念,spring的事务是对数据库的事务的封装。
封装原理:spring通过aop对bean创建代理对象来实现事务管理

Spring 事务管理接口介绍

Spring 框架中,事务管理相关最重要的 3 个接口如下:

PlatformTransactionManager: 事务管理器,核心。
TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。
TransactionStatus: 事务运行状态。

我们可以把 PlatformTransactionManager 接口看作是事务上层的管理者,而 TransactionDefinition 和 TransactionStatus 这两个接口可以看作是事物的描述。
PlatformTransactionManager 会根据 TransactionDefinition 的定义比如事务超时时间、隔离级别、传播行为等来进行事务管理 ,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态,比如是否新事务、是否可以回滚等等。

PlatformTransactionManager :事务管理接口

Spring 并不直接管理事务,而是提供了多种事务管理器 ,PlatformTransactionManager 就是其中之一的事务管理接口。

通过这个接口,Spring 为各个平台JDBC/Mybatis(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

PlatformTransactionManager接口中定义了三个方法:

public interface PlatformTransactionManager {
    //获得事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

为什么要定义或者说抽象出来PlatformTransactionManager这个接口呢?

主要是因为要将事务管理行为抽象出来,然后不同的平台去实现它,这样我们可以保证提供给外部的行为不变,方便我们扩展。

TransactionDefinition:事务属性

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数就是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。

那么什么是 事务属性 呢?

事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。

事务属性包含了 5 个方面:

TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;
    // 返回事务的传播行为,默认值为 REQUIRED。
    int getPropagationBehavior();
    //返回事务的隔离级别,默认值是 DEFAULT
    int getIsolationLevel();
    // 返回事务的超时时间,默认值为-1。
    //如果超过该时间限制但事务还没有完成,则自动回滚事务。
    int getTimeout();
    // 返回是否为只读事务,默认值为 false
    boolean isReadOnly();

    @Nullable
    String getName();
}

五大属性详解

TransactionStatus:事务状态

TransactionStatus接口用来记录事务的状态 ,该接口定义了一组方法,用来获取或判断事务的相应状态信息。

有如下状态信息:

public interface TransactionStatus{
    boolean isNewTransaction(); // 是否是新的事物
    boolean hasSavepoint(); // 是否有恢复点
    void setRollbackOnly();  // 设置为只回滚
    boolean isRollbackOnly(); // 是否为只回滚
    boolean isCompleted; // 是否已完成
}
spring事物使用 五大属性 事务失效的7种情况

1、未启用spring事务管理功能
@EnableTransactionManagement 注解不要忘了

2、方法不是public类型的

4、必须通过代理对象访问目标方法,事务才会生效,普通对象访问会失效。
spring的事物是怎么实现的?通过aop给目标对象生成代理对象,然后通过代理对象拦截目标方法的执行,在目标方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。

看下面代码,当外部直接调用m1的时候,m2方法的事务会生效么?

@Component
public class UserService {
    public void m1(){
        this.m2();
    }
    
    @Transactional
    public void m2(){
        //执行db操作
    }
}

显然不会生效,因为m1中通过this的方式调用了m2方法,而this并不是代理对象,this.m2()不会被事务拦截器,所以事务是无效的,如果外部直接通过UserService这个bean来调用m2方法,事务是有效的,上面代码可以做一下调整,如下,@1在UserService中注入了自己,此时m1中的m2事务是生效的

@Component
public class UserService {
    @Autowired //@1
    private UserService userService;

    public void m1() {
       userService.m2();
    }

    @Transactional
    public void m2() {
        //执行db操作
    }
}

5、发生异常

6、异常被吞了
当业务方法抛出异常,spring感知到异常的时候,才会做事务回滚的操作,若方法内部将异常给吞了,那么事务无法感知到异常了,事务就不会回滚了。

7、业务代码和事务代码必须在同一个线程中
spring事务实现中使用了ThreadLocal,这就要求业务代码和事务代码必须在一个线程中,数据才可以共享,才会受spring事务的控制。
比如下面代码,方法内部的子线程内部执行的事务操作将不受m1方法上spring事务的控制,这个大家一定要注意

@Transactional
public void m1() {
    new Thread() {
        一系列事务操作
    }.start();
}
如何快速定位事务相关bug?

方式1:看日志
如果你使用了logback或者log4j来输出日志,可以修改一下日志级别为debug模式,可以看到事务的详细执行日志,帮助你定位错误

方式2:调试代码
如果你对源码比较了解,那么你会知道被spring管理事务的业务方法,执行的时候都会被TransactionInterceptor拦截器拦截,会进入到它的invoke方法中,咱们可以在invoke方法中设置一些断点,可以看到详细的执行过程,排错也就比较容易了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/329084.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号