SpringBoot基础之声明式事务和切面事务和编程式事务

这篇具有很好参考价值的文章主要介绍了SpringBoot基础之声明式事务和切面事务和编程式事务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。



前言

事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性。
springBoot中两种事务的实现方式,编程式事务配置和声明式事务配置还有切面事务 还有以后的分布式事务

详情参考 这篇


一、事务特性

SpringBoot基础之声明式事务和切面事务和编程式事务

  • 原子性(Atomicity):
    事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用;
  • 一致性(Consistency):
    一旦事务完成(不管是成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏;
  • 隔离性(Isolation):
    可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏;
  • 持久性(Durability):
    一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中;

Spring 框架中,涉及到事务管理的 API 大约有100个左右,其中最重要的有三个:TransactionDefinition、PlatformTransactionManager、TransactionStatus。所谓事务管理,其实就是”按照给定的事务规则来执行提交或者回滚操作”。”给定的事务规则”就是用 TransactionDefinition 表示的,”按照……来执行提交或者回滚操作”便是用 PlatformTransactionManager 来表示,而 TransactionStatus 用于表示一个运行着的事务的状态。打一个不恰当的比喻,TransactionDefinition 与 TransactionStatus 的关系就像程序和进程的关系。

开启事务

@EnableTransactionManagement

二、事务的隔离级别

和数据库中的事务级别是一样的 都会出现事务本身应该有的问题
SpringBoot基础之声明式事务和切面事务和编程式事务

三、事务的传播行为

SpringBoot基础之声明式事务和切面事务和编程式事务

四、 Springboot事务

1.Springboot声明式事务

声明式事务是建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。

DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。

根据代理机制的不同,总结了五种Spring事务的配置方式,如下图:

SpringBoot基础之声明式事务和切面事务和编程式事务

声明式事务@Transactional可以使用在类上,也可以使用在public方法上. 如果是使用在类上,则是对所有的public方法都开启事务,如果类和方法上都有则方法上的事务生效
在类上

@Transactional(rollbackFor=Exception.class)
public class TransactionServiceImpl implements TransactionService {
}

在方法上

@Override
@Transactional(rollbackFor=Exception.class)
public void t1(Student one) {
}

声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

优点:

编程式事务每次实现都要单独实现,但业务量大且功能复杂时,使用编程性事务无疑是痛苦的;而声明式事务不同,声明式事务属于非侵入性,不会影响业务逻辑的实现,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中;

非侵入式的开发方式,声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持;

缺点:

最细粒度只能是作用到方法级别,无法做到像编程事务那样可以作用到代码块级别;

实现方式:

使用拦截器:基于TransactionInterceptor 类来实施声明式事务管理功能(Spring最初提供的实现方式);

Bean和代理:基于 TransactionProxyFactoryBean的声明式事务管理

使用tx标签配置的拦截器:基于tx和aop名字空间的xml配置文件(基于Aspectj AOP配置事务);
全注解:基于@Transactional注解;

@Transactional的参数

SpringBoot基础之声明式事务和切面事务和编程式事务

声明式事务的约定流程:

首先Spring通过事务管理器(PlatformTransactionManager的子类)创建事务,与此同时会把事务定义中的隔离级别、超时时间等属性根据配置内容往事务上设置。而根据传播行为配置采取一种特定的策略,后面会谈到传播行为的使用问题,这是Spring根据配置完成的内容,你只需要配置,无须编码。然后,启动开发者提供的业务代码,我们知道Spring会通过反射的方式调度开发者的业务代码,但是反射的结果可能是正常返回或者产生异常返回,那么它给的约定是只要发生异常,并且符合事务定义类回滚条件的,Spring就会将数据库事务回滚,否则将数据库事务提交,这也是Spring自己完成的
  SpringBoot基础之声明式事务和切面事务和编程式事务

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,它的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

2. Springboot编程式事务

编程式事务:
是侵入性事务管理,直接使用底层的PlatformTransactionManager、使用TransactionTemplate(Spring推荐使用);
编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法;

@Autowired 
private TransactionTemplate transactionTemplate;
@Override
  public final void save2() {
   transactionTemplate.execute((status)->{
            mapper.saveStudent(newOne());
            mapper.saveStudent(newOne());
            return Boolean.TRUE;
        });
  }

这样两个mapper.saveStudent(newOne());就在一个事务中执行了

SpringBoo切面编程式事务

SpringBoo切面编程式事务应该是声明式事务的一种具体体现
此种方式基于AOP功能,所以需要添加
详细看这篇

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

配置类

@Aspect
@Configuration
public class MyTransactionConfig {

    /**
     * 配置方法过期时间,默认-1,永不超时
     */
    private final static int TX_METHOD_TIME_OUT = 10;

   /**
     * 全局事务位置配置 在哪些地方需要进行事务处理
     * 配置切入点表达式
     */
    private static final String POITCUT_EXPRESSION = "execution(* zdc.enterprise.service.impl.*.*(..))";

    @Autowired
    private PlatformTransactionManager platformTransactionManager;


    @Bean
    public TransactionInterceptor txadvice() {

        /*只读事物、不做更新删除等*/
        /*事务管理规则*/
        RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
        /*设置当前事务是否为只读事务,true为只读*/
        readOnlyRule.setReadOnly(true);
        /* transactiondefinition 定义事务的隔离级别;
         *如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。*/
        readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);

         /*增删改事务规则*/
        RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
        /*抛出异常后执行切点回滚 建议自定义异常*/
        requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        /*PROPAGATION_REQUIRED:事务隔离性为1,若当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 */
        requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        /*设置事务失效时间,超过10秒*/
        requireRule.setTimeout(TX_METHOD_TIME_OUT);

        /** 配置事务管理规则
         nameMap声明具备需要管理事务的方法名.
         这里使用addTransactionalMethod  使用setNameMap
         */
        Map<String, TransactionAttribute> nameMap = new HashMap<>();
        nameMap.put("add*", requireRule);
        nameMap.put("save*", requireRule);
        nameMap.put("insert*", requireRule);
        nameMap.put("update*", requireRule);
        nameMap.put("delete*", requireRule);
        nameMap.put("remove*", requireRule);

        /*进行批量操作时*/
        nameMap.put("batch*", requireRule);
        nameMap.put("get*", readOnlyRule);
        nameMap.put("query*", readOnlyRule);
        nameMap.put("find*", readOnlyRule);
        nameMap.put("select*", readOnlyRule);
        nameMap.put("count*", readOnlyRule);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.setNameMap(nameMap);

        TransactionInterceptor transactionInterceptor = new TransactionInterceptor(platformTransactionManager, source);

        return transactionInterceptor;
    }

    /**
     * 设置切面=切点pointcut+通知TxAdvice
     * @return
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(POITCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txadvice());
    }
}

有了这个切面配置类,就不要用在类或者每个方法上使用@Transactional了,当然方法名前缀要能和设置的匹配上. RuleBasedTransactionAttribute的参数大致和@Transactional的参数相同,里面有详细的注释,就不过多解释了文章来源地址https://www.toymoban.com/news/detail-433511.html

到了这里,关于SpringBoot基础之声明式事务和切面事务和编程式事务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 32、启用 HTTP 响应压缩和编程式配置Web应用

    就是前端页面如果改动的比较多,那么响应就会比较慢,可以通过设置HTTP响应压缩来提高响应,如果前端改动少,那么就不需要启动这个响应压缩。 就是获取到 WebServer 这个Web服务器,然后修饰里面的一些东西,比如端口号,比如对某些前端页面启用 HTTP压缩 的功能。 方法

    2024年02月11日
    浏览(35)
  • SpringCloud系列篇:核心组件之声明式HTTP客户端组件【远程消费】

    接下来看看由辉辉所写的关于SpringCloud的相关操作吧 目录 🥳🥳Welcome Huihui\\\'s Code World ! !🥳🥳 一. 远程消费组件是什么 二. 远程消费组件的详解 场景模拟 代码实操 1.生产者 2.消费者 3.复杂参数的处理 DTO 属性赋值          声明式HTTP客户端组件是一种用于简化HTTP请求的

    2024年02月02日
    浏览(28)
  • 微信小程序开发学习之页面导航(声明式导航和编程式导航)

    页面导航指的是页面之间的相互跳转。 小程序中实现页面导航的两种方式: 声明式导航 ● 在页面上声明一个 navigator 导航组件 ● 通过点击 navigator 组件来实现页面的跳转 编程式导航 ● 调用小程序的导航API,实现页面的跳转 1.1.1. 导航到tabBar页面 tabBar 页面指的是被配置为

    2024年02月15日
    浏览(41)
  • ArkUI框架之声明式 UI 条件渲染&声明周期以及案例美化实战运用【OpenHarmony/HarmonyOS】

    1.1.1 用户名位数判断 实现用户名位数判断可以直接在build方法函数里进行写if语句的条件判断。 我们把用户名改到超出五位查看效果如下:

    2024年02月06日
    浏览(29)
  • Spring 事务(编程式事务、声明式事务@Transactional、事务隔离级别、事务传播机制)

    本篇重点总结: 在 Spring 项目中使用事务,有两种方式:编程式手动操作和声明式自动提交,声明式自动提交使用最多,只需要在方法上添加注解 @Transactional 设置事务的隔离级别 @Transactional(isolation = Isolation.SERIALIZABLE),Spring 中的事务隔离级别有5种 设置事务的传播机制 @Tra

    2024年02月03日
    浏览(32)
  • Spring 编程式事务 (Spring 重点)

    Spring ⼿动操作事务和 MySQL操作事务类似,有 3 个重要操作步骤:  • 开启事务(获取事务)  • 提交事务  • 回滚事务 SpringBoot 内置了两个对象: 1. DataSourceTransactionManager 事务管理器.⽤来获取事务(开启事务),提交或回滚事务的 2. TransactionDefinition 是事务的属性,在获取事务的时候

    2024年01月24日
    浏览(26)
  • Spring事务切面_传播属性(8)

    目录 1. 传播属性 2. 案例分享 2.1 测试说明 2.2  Propagation.REQUIRED 演示 案例1: 案例2: 案例3: 案例4: 总结1: 案例5: 案例6: 特殊的传播属性 NESTED 错误使用 案例6的解决方案: 3. 带着问题看源码 3.1 类分析: 3.2 源码分析 3.2.1 事务创建  3.2.2 事务的链式调用 源码case: 3

    2023年04月10日
    浏览(29)
  • 【前端知识】React 基础巩固(十四)——JSX 的转换过程和声明式编程

    jsx 仅仅只是 React.createElement(component, props, …children)函数的语法糖 所有的 jsx 最终都会被转换成 React.createElement 的函数调用 createElement 需要传递三个参数: type 当前 ReactElement 的类型 如果是标签元素,那么就使用字符串表示 “div” 如果是组件元素,那么就直接使用组件的名称

    2024年02月09日
    浏览(72)
  • Springboot切面打印日志

    切面打印完整日志,以下代码用于扫描@RestController 注解修饰的接口,并打印相关日志

    2024年02月14日
    浏览(28)
  • SpringBoot作日志切面记录

    目录 1.WebLogAspect 2.配置log4j2.yml 3.效果 话不多说,直接上代码:  1.WebLogAspect         在上面的代码示例中,我们定义了一个 WebLogAspect 切面,并通过 @Pointcut 注解指定了切点为所有 com.example.controller 包下的公共方法。在切面中,我们使用了 @Before 注解来记录请求信息,在

    2024年02月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包