@Transactional实现原理及失效的三种情况

@Transactional实现原理

Transactional是spring中定义的事务注解,在方法或类上加该注解开启事务。主要是通过反射获取当前对象的注解信息,利用AOP(代理模式)对编程式事务进行封装实现

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package org.springframework.transaction.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";String[] label() default {};Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default -1;String timeoutString() default "";boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}

手动实现事务自定义注解

自定义注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {//自定义注解的属性int id() default 0;String name() default "默认名称";String[] arrays() default {};String title() default "默认标题";
}

封装编程式事务

@Component
@Scope("prototype")
public class TransactionUtil {// 全局接受事务状态private TransactionStatus transactionStatus;// 获取事务源@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;// 开启事务public TransactionStatus begin() {System.out.println("开启事务");transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());return transactionStatus;}// 提交事务public void commit(TransactionStatus transaction) {System.out.println("提交事务");if (dataSourceTransactionManager != null) {dataSourceTransactionManager.commit(transaction);}}public void rollback(TransactionStatus transaction) {System.out.println("回滚事务");if (dataSourceTransactionManager != null) {dataSourceTransactionManager.rollback(transaction);}}
}

AOP触发事务

@Component
@Aspect
public class AopTransaction {@Autowiredprivate TransactionUtil transactionUtil;private TransactionStatus transactionStatus;/*** 环绕通知,在方法 前---后 处理事情** @param pjp 切入点*/@Around("execution(* com.sl.service.*.*(..))")public void around(ProceedingJoinPoint pjp) throws Throwable {// 获取方法的注解MyAnnotation annotation = this.getMethodMyAnnotation(pjp);// 判断是否需要开启事务transactionStatus = begin(annotation);// 调用目标代理对象方法pjp.proceed();// 判断关闭事务commit(transactionStatus);}/*** 获取代理方法上的事务注解** @param pjp* @return* @throws Exception*/private MyAnnotation getMethodMyAnnotation(ProceedingJoinPoint pjp) throws Exception {// 获取代理对象的方法String methodName = pjp.getSignature().getName();// 获取目标对象Class<?> classTarget = pjp.getTarget().getClass();// 获取目标对象类型Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();// 获取目标对象方法Method objMethod = classTarget.getMethod(methodName, par);// 获取该方法上的事务注解MyAnnotation annotation = objMethod.getDeclaredAnnotation(MyAnnotation.class);return annotation;}/*** 开启事务** @param annotation* @return*/private TransactionStatus begin(MyAnnotation annotation) {if (annotation == null) {return null;}return transactionUtil.begin();}/*** 提交事务** @param transactionStatus*/private void commit(TransactionStatus transactionStatus) {if (transactionStatus != null) {transactionUtil.commit(transactionStatus);}}/*** 异常通知进行 回滚事务*/@AfterThrowing("execution(* com.sl.service.*.*(..))")public void afterThrowing() {// 获取当前事务 直接回滚if (transactionStatus != null) {transactionUtil.rollback(transactionStatus);}}
}

失效第一种

Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用

@Service
public class TestServiceImpl {@AutowiredTestMapper testMapper;@Transactionalvoid insert(SysUserOrgPo sysUserOrgPo) {int re = testMapper.insert(sysUserOrgPo);if (re > 0) {throw new BaseException("发生异常")}testMapper.insert(new SysUserOrgPo("张三","1234"));}}

此时调用此方法, @Transactional会失效,testMapper.insert(sysUserOrgPo)不会回滚,根本原因是@Transactional的实现通过的AOP实现,也就是动态代理实现,如果方法上的修饰符都是非public的时候,那么将不会创建代理对象,所以事务也就不生效

失效第二种

在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启

@Service
public class TestServiceImpl {@AutowiredTestMapper testMapper;@Transactionalpublic void insert(SysUserOrgPo sysUserOrgPo) {int re = testMapper.insert(sysUserOrgPo);if (re > 0) {throw new BaseException("发生异常")}testMapper.insert(new SysUserOrgPo("张三","1234"));}public void testInnerInvoke(){//内部调用事务方法,@Transactional失效testServiceImpl.insertTestInnerInvoke();}}

如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过了代理对象,肯定就是没有代理逻辑了 

失效第三种 

事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚,原因是实现逻辑是只有捕获到异常才会回滚事务,列举源码如下

try {retVal = invocation.proceedWithInvocation();
} catch (Throwable var20) {// 事务回滚this.completeTransactionAfterThrowing(txInfo, var20);throw var20;
} finally {this.cleanupTransactionInfo(txInfo);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/29392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win11版本21H2怎么升级为23H2?升级详细步骤在此!

在Win11电脑操作中&#xff0c;用户目前使用的版本是21H2&#xff0c;现在想体验23H2版本的先进功能&#xff0c;但不知道要怎么操作才能将系统版本升级为23H2&#xff1f;接下来小编给大家介绍详细的升级方法步骤&#xff0c;助力大家轻松完成系统版本升级操作。 方法一&#…

PostgreSQL源码分析——CHECKPOINT

checkpoint源码分析 因为检查点checkpoint相关的代码不是一篇文章就能分析完的&#xff0c;所以&#xff0c;相关的代码与逻辑可能会不连续&#xff0c;需要后续结合上下文理解。这里只列出了其中一部分。 其核心代码在&#xff1a;src/backend/postmaster/checkpointer.c以及…

05眼动识别软件详情2波形优化-滤波

对应视频链接点击直达 01项目点击下载&#xff0c;可直接运行&#xff08;含数据库&#xff09; 05眼动识别软件详情2 对应视频链接点击直达期望的数据展示数据波形对比如何实现几种常用滤波介绍维纳滤波巴特沃斯滤波器中值滤波排序滤波 推荐 结语其他以下是废话 原始数据的波…

CentOS 7.9上创建的JBOD阵列恢复(二)

系列文章目录 CentOS 7.9上创建JBOD&#xff08;一&#xff09; CentOS 7.9检测硬盘坏区、实物定位&#xff08;三&#xff09; 文章目录 系列文章目录前言一、用命令查看是否认到盘二、直接组JBOD三、挂载到新目录四、查看原数据总结 前言 在CentOS 7.9上创建了一个软阵列JB…

代码随想录算法训练营第四十二天| 1049. 最后一块石头的重量 II、 494. 目标和

LeetCode 1049. 最后一块石头的重量 II 题目链接&#xff1a;https://leetcode.cn/problems/last-stone-weight-ii/description/ 文章链接&#xff1a;https://programmercarl.com/1049.%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E7%9F%B3%E5%A4%B4%E7%9A%84%E9%87%8D%E9%87%8FII…

SQL触发器基本结构

1. 修改分隔符的符号 delimiter $$ $$或者//都可以 2.创建触发器的名称 create trigger 函数名称 3. 什么样的操作会触发&#xff0c;操作的那个表 after&#xff1a;....之后触发 befor&#xff1a;....之前触发 insert&#xff1a;插入被触发 update&#xff1a;修改被触发 …

Kibana 一步步可视化实战构建步骤全集

今早读者朋友圈提及&#xff1a;《一本书讲透Elasticsearch》适合入门级体系化阅读&#xff0c;书中的3个项目实战&#xff0c;很适合实操&#xff0c;但是在建立Kibana可视化的过程中&#xff0c;书中没有明确构建步骤&#xff0c;在实操中会有缺憾。 我解释一下&#xff1a; …

CPU与GPU的原理不同

CPU&#xff08;中央处理器&#xff09;和GPU&#xff08;图形处理器&#xff09;在设计原理上有很大的不同。CPU是通用的计算核心&#xff0c;擅长处理复杂的控制流和数据结构&#xff0c;而GPU则是为了并行处理大量相似的计算任务而设计的。二者是计算机系统中两种不同类型的…

AI实战 | 使用元器打造浪漫仪式小管家

浪漫仪式小管家 以前我们曾经打造过学习助手和待办助手,但这一次,我们决定创造一个与众不同的智能体,而浪漫将成为我们的主题。我们选择浪漫作为主题,是因为我们感到在之前的打造过程中缺乏了一些仪式感,无法给对方带来真正的惊喜。因此,这一次我们计划慢慢调试,将它发…

vim 显示行号

在 Vim 中&#xff0c;你可以通过几种不同的方式来显示行号。以下是两种常用的方法&#xff1a; 临时显示行号&#xff1a; 当你打开 Vim 并想要临时查看文件的行号时&#xff0c;你可以使用 :set number 命令。这个命令会在当前 Vim 会话中显示行号。如果你想要关闭行号显示&a…

Python xml.dom.minidom 读取XML元素

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 什么是 XML&#xff1f; XML&#xff08;可扩展标记语言&#xff09;是一种用于描述数据结构和交换数据的标记语言。它被广泛用于 Web 应用程序中&#xff0c;用于存储和传输数据。XML 具有自描述性&#xff0c;因此…

GitHub|GitLab它们的区别是什么?

GitLab 和 GitHub 都是基于 Git 版本控制系统提供服务的平台&#xff0c;但它们是两个不同的产品&#xff0c;各自有着不同的特点和目标用户群。下面是对它们的基本解释和一些关键差异&#xff1a; GitHub 概述&#xff1a;GitHub 是全球最大的开源代码托管平台&#xff0c;由…

yocto根文件系统如何配置静态IP地址

在Yocto根文件系统中配置静态IP地址&#xff0c;你可以参考以下步骤。请注意&#xff0c;这些步骤可能会因Yocto版本和具体硬件平台的不同而略有差异。 1. 获取网络配置信息 首先&#xff0c;你需要从网络运维方获取分配的IP地址、子网掩码、默认网关和DNS信息。 2. 确定配置文…

文生视频开源产品的一些调研(一)

笔者尝试AI视频生成的几个特点&#xff1a; 玄学prompt&#xff0c;每个视频的prompt可能也需要微调很多次&#xff0c;需要找到使用模型的最佳prompt词组合&#xff0c;不恰当的比喻&#xff0c;骑自行车&#xff0c;座位高度等都是人与车彼此熟悉玄学生成&#xff0c;因为需…

第二证券:英伟达“利空”?!黄仁勋逢高又卖超2亿

时隔9个月&#xff0c;黄仁勋再次套现英伟达&#xff0c;股价小幅下跌。 当地时间6月17日周一&#xff0c;美股三大股指全线收涨。到收盘&#xff0c;道指涨0.49%&#xff0c;纳指涨0.95%&#xff0c;标普500指数涨0.77%。 英伟达CEO黄仁勋时隔9个月再度出售英伟达股票。最新…

基于spring的个人理财系统

需求概述 建设目标 个人理财项目的项目建设目标如下&#xff1a;完成用户注册、登录、用户唯一性验证、记账管理、预算管理、个人信息、修改密码等功能&#xff0c;实现完整的理财流程。 运行环境 1&#xff0e;系统硬件环境 &#xff08;1&#xff09;服务器端 名称 配置…

STM32学习笔记(六)--引脚重映射详解

STM32F103C8T6引脚定义&#xff1a; 在STM32微控制器中&#xff0c;外设引脚的复用功能&#xff08;Alternate Function&#xff0c;AF&#xff09;有时会出现冲突&#xff0c;例如当USART2_CTS和TIM2_CH1同时需要使用相同的引脚时。此时&#xff0c;可以通过引脚重映射功能&am…

02-Git命令

1.初始化仓库&#xff1a; git init 2.查看文件状态&#xff1a; git status 3.添加到暂存区 &#xff1a;git add 文件名 git add . 4.提交到本地仓库&#xff1a; git commit -m "提交信息" 5.拉去远程最新代码&#xff1a; git pull 远程地址 分支 6.解决冲突 …

入门三.HTB--Dancing(6.18)

大佬 https://www.cnblogs.com/Hekeats-L/p/16535920.html 任务1 SMB 即Server Message Block&#xff08;服务器消息块&#xff09;&#xff0c;是一种文件共享协议。当文件原件在你的A电脑上&#xff0c;而你想在局域网下用你的手机、iPad或是另一台电脑来访问A电脑上的该文…

nginx+keepalived高可用搭建的详细步骤

现在有2台机器&#xff0c;10.5.100.36 和 10.5.100.37&#xff0c;分别在这2台机器上面部署nginx和keepalived&#xff0c;然后利用keepalived对nginx做高可用。 1&#xff0c;安装好nginx&#xff0c;使用的是 yum install nginx -y2&#xff0c;修改nginx的配置文件nginx.…