11-@Transaction与AOP冲突解决

如题,最近碰到了一个问题,在public方法上添加@Transaction没有生效,事务没有回滚。
我自己模拟了一个功能,向数据库表User里面插入用户数据。说一下代码背景,
数据库MySQL,持久化层Mybatis,项目使用SpringBoot。
数据表User如下,已有一条数据:
table表:User
下面是代码

  1. Application启动类
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import tk.mybatis.spring.annotation.MapperScan;@SpringBootApplication(scanBasePackages = {"com.example.demo","com.example.demo.dao"})
//启动事务
@EnableTransactionManagement
//mapper接口扫描
@MapperScan("com.example.demo.dao")
@RestController
public class DemoApplication {@GetMapping("/")String home() {return "Spring is here!";}public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
  1. 实体类User,对应数据表user表
@Data
@Table(name = "`user`")
public class User {@Id@Column(name = "`id`")@GeneratedValue(strategy = GenerationType.IDENTITY)private int id;@Column(name = "`name`")private String name;@Column(name = "`created_time`")private Date createdTime;
}
  1. Mapper类
package com.example.demo.dao;import com.example.demo.domain.po.User;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;/*** TOrderMapper** @author zhouxy@133.cn* @date 2022/8/15**/
@Repository
public interface UserMapper extends Mapper<User>, MySqlMapper<User> {
}
  1. Service接口,处理业务逻辑,添加@Transaction
package com.example.demo.service;import com.example.demo.domain.po.User;
import org.springframework.stereotype.Service;/*** @Description: TODO* @Author: zhouxy* @CreateTime: 2023-10-17*/
public interface IUserService {Integer addUser(User user);
}
  1. service实现类
package com.example.demo.service.impl;import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @Description: TODO* @Author: zhouxy* @CreateTime: 2023-10-17*/
@Service
public class UserService implements IUserService {@Autowiredprivate UserMapper userMapper;@Override@Transactionalpublic Integer addUser(User user) {Integer result = userMapper.insertSelective(user);}
}
  1. AOP类
package com.example.demo.aop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;/*** @Description: TODO* @Author: zhouxy* @CreateTime: 2023-05-17*/
@Aspect
@Component
@Slf4j
public class LogAop {@Pointcut(value = "execution(* com.example.demo.service.*.*(..))")public void controller() {log.info("223432");}@Around("controller()")public Object around(ProceedingJoinPoint joinPoint) {log.info("before================");try {Object res = joinPoint.proceed();return res;} catch (Throwable throwable) {log.error("", throwable);}finally {log.info("after================");}return null;}
}
  1. 测试类
import com.example.demo.DemoApplication;
import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;/*** MybatisTest** @author zhouxy@133.cn* @date 2021/7/20**/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class MybatisTest {@Autowiredprivate IUserService userService;@Testpublic void test() {User user = new User();user.setName("LISI222");userService.addUser(user);}
}

当正常执行的时候,会在数据库中插入数据。
table表:User

打印日志:
在这里插入图片描述

此时在实现类中加入一行异常,看一下出现异常之后,事务是否会回滚,数据能否成功插入到数据表中。

package com.example.demo.service.impl;import com.example.demo.dao.UserMapper;
import com.example.demo.domain.po.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** @Description: TODO* @Author: zhouxy* @CreateTime: 2023-10-17*/
@Service
public class UserService implements IUserService {@Autowiredprivate UserMapper userMapper;@Override@Transactionalpublic Integer addUser(User user) {Integer result = userMapper.insertSelective(user);//添加一行异常,查看事务是否会因为抛出异常回滚刚才的插入操作throw new RuntimeException();}
}

我们看执行完之后,数据库的变化,我刚才插入的是用户:LISI222
在这里插入图片描述

显示的是插入成功,看后台日志显示,事务并没有做回滚操作,说明当前事务并没有捕获到异常信息。仔细分析日志头尾可知,日志打印操作包裹了service实现类的addUser方法,应该是aop操作在@Transaction之前执行,导致异常被aop处理了,aop最终也没有抛出异常,所以@Transaction方法没有捕获到异常信息。

2023-11-24 10:53:24.418  INFO [,,,] 29600 --- [           main] com.example.demo.aop.LogAop              : before================
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c3884f5]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5542418c] will be managed by Spring
==>  Preparing: INSERT INTO `user` ( `id`,`name` ) VALUES( ?,? )
==> Parameters: 0(Integer), LISI222(String)
<==    Updates: 1
==>  Executing: SELECT LAST_INSERT_ID()
<==    Columns: LAST_INSERT_ID()
<==        Row: 11
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c3884f5]
2023-11-24 10:53:24.566 ERROR [,,,] 29600 --- [           main] com.example.demo.aop.LogAop              : java.lang.RuntimeException: nullat com.example.demo.service.impl.UserService.addUser(UserService.java:24) ~[classes/:na]at com.example.demo.service.impl.UserService$$FastClassBySpringCGLIB$$9c38b50f.invoke(<generated>) ~[classes/:na]····异常信息打印,忽略2023-11-24 10:53:24.566  INFO [,,,] 29600 --- [           main] com.example.demo.aop.LogAop              : after================
这里仍然正常提交事务,说明没有捕获到异常信息
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c3884f5]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c3884f5]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6c3884f5]

现在是因为aop中没有将异常抛出,做了友好化处理,将异常处理成了返回了错误码。所以需要在aop处理返回结果之前,事务就要捕获到当前事务中抛出的异常并进行回滚或者不提交事务。
我在网上查找资料的时候查找到@Order注解,@Order的作用是定义Spring IOC容器中Bean的执行顺序的优先级(这里的顺序也可以理解为存放到容器中的先后顺序),所以我给LogAop类加了一个@Order注解,让LogAOP在最后执行,这样@Transaction类就可以提前执行,捕获异常,回滚数据。@Order默认为最低优先级,因此可以直接设置@Order即可

@Aspect
@Component
@Slf4j
@Order(10) //定义LogAOP的顺序最后执行,值越高,优先级越低
public class LogAop {
·····
}

这次再执行一遍,查看是否成功回滚事务。
在这里插入图片描述
再看下日志,事务在aop之前执行完成。

2023-11-24 10:59:04.879  INFO [,,,] 28412 --- [           main] com.example.demo.aop.LogAop              : before================
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@786e2c5e]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@78854721] will be managed by Spring
==>  Preparing: INSERT INTO `user` ( `id`,`name` ) VALUES( ?,? )
==> Parameters: 0(Integer), LISI333(String)
<==    Updates: 1
==>  Executing: SELECT LAST_INSERT_ID()
<==    Columns: LAST_INSERT_ID()
<==        Row: 12
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@786e2c5e]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@786e2c5e]
这里关闭了事务,并且没有提交操作。
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@786e2c5e]
2023-11-24 10:59:05.271 ERROR [,,,] 28412 --- [           main] com.example.demo.aop.LogAop              : java.lang.RuntimeException: nullat com.example.demo.service.impl.UserService.addUser(UserService.java:24) ~[classes/:na]at com.example.demo.service.impl.UserService$$FastClassBySpringCGLIB$$9c38b50f.invoke(<generated>) ~[classes/:na]
2023-11-24 10:59:05.272  INFO [,,,] 28412 --- [           main] com.example.demo.aop.LogAop              : after================

使用@Order注解可以调整运行级别,但是需注意一个问题,aop中不要做一些业务操作,因为transaction不会捕获到aop中抛出的异常。可以使用try…catch捕获aop中的数据库操作,并进行回滚。

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

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

相关文章

Vue3(setup)中使用vue-cropper图片上传裁剪插件,复制代码直接使用

最近在项目中用到上传裁剪&#xff0c;看了一下代码&#xff0c;觉得这插件可可以。梳理了一下代码分享给大家 前端UI组件element-plus 如果你也用到了 &#xff0c;快速帮你解决了问题,别忘记点赞收藏 1.首先看效果图 因为版本vue-cropper 众多 &#xff0c;虽然网上有各…

阿里云windwos 安装oracle数据库,外部用工具连接不上,只能在服务器本机通过127.0.0.1 连接

1. 首先检查阿里云服务器安全组端口是否开放 oracle 数据库端口 2. 其次找到oracle 安装的目录&#xff0c;打开这俩个文件&#xff0c;将localhost 修改为 服务器本机名称 3.重启oracle 监听服务&#xff0c;就可以连接了

技术部工作职能规划分析

前言 技术部的职能。以下是一个基本的框架,其中涵盖了技术部在公司中的关键职能和子职能。 主要职能 技术部门的主要职能分为以下几个板块: - 技术规划与战略: 制定技术规划和战略,与业务团队合作确定技术需求。 研究和预测技术趋势,引领公司在技术创新和数字化转型方…

基于springboot实现智慧党建系统项目【项目源码】计算机毕业设计

基于springboot实现智慧党建系统演示 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点&#xff0c;而且Java是开源的&#xff0c;拥有全世界最大的开发者专业社群&#xff0c;所以…

【Unity细节】Unity中为什么用字符串加载对象,检查多便都加载不出来—(命名细节)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

【Python】itertools模块,补充:可迭代对象、迭代器

Python中 itertools模块创建高效迭代器、处理序列数据集。 此模块所有函数返回迭代器&#xff0c;可用for循环获取迭代器中的内容&#xff0c;也可用list(...)用列表形式显示内容。 import itertools[ x for x in dir(itertools) if not x.startswith(_)] # 结果&#xff1a;…

什么是网络爬虫技术?它的重要用途有哪些?

网络爬虫&#xff08;Web Crawler&#xff09;是一种自动化的网页浏览程序&#xff0c;能够根据一定的规则和算法&#xff0c;从互联网上抓取和收集数据。网络爬虫技术是随着互联网的发展而逐渐成熟的一种技术&#xff0c;它在搜索引擎、数据挖掘、信息处理等领域发挥着越来越重…

通俗理解词向量模型,预训练模型,Transfomer,Bert和GPT的发展脉络和如何实践

最近研究GPT&#xff0c;深入的从transfomer的原理和代码看来一下&#xff0c;现在把学习的资料和自己的理解整理一下。 这个文章写的很通俗易懂&#xff0c;把transformer的来龙去脉&#xff0c;还举例了很多不错的例子。 Transformer通俗笔记&#xff1a;从Word2Vec、Seq2S…

6 个有效且可用的顶级 Android 数据恢复工具

经过测试 42 种数据恢复软件产品&#xff0c;发现奇客数据恢复安卓版是 Android 设备的最佳选择。 过去几十年来&#xff0c;我一直在科技行业工作&#xff0c;经常帮助人们应对计算机灾难&#xff0c;包括丢失数据。 Android 数据恢复应用程序不在您的设备上运行&#xff0c…

IDEA中注释快捷键及模板

单行注释 将光标放置于要注释所在行&#xff0c;使用 Ctrl /&#xff0c; 添加行注释&#xff0c;再次使用&#xff0c;去掉行注释 若需要将多行进行单行注释&#xff0c;只需要选中要注释的多行&#xff0c;然后使用 Ctrl /&#xff0c; 添加行注释&#xff0c;再次使用&a…

聚焦数据要素跨域运营,构建数据要素统一大市场地方数据局局长闭门会正式召开

11月23日&#xff0c;在第二届全球数字贸易博览会期间&#xff0c;杭州市数据资源局、中国电子云、杭州数据交易所联合组织各地数据主管部门&#xff0c;召开构建数据要素统一大市场地方数据局局长闭门会&#xff0c;交流数据要素统一大市场构建思路&#xff0c;共探公共数据运…

基于springboot实现农机电招平台系统项目【项目源码+论文说明】

基于springboot实现农机电招平台系统演示 摘要 随着农机电招行业的不断发展&#xff0c;农机电招在现实生活中的使用和普及&#xff0c;农机电招行业成为近年内出现的一个新行业&#xff0c;并且能够成为大群众广为认可和接受的行为和选择。设计农机电招平台的目的就是借助计算…

软件开发中对图片的加工处理的一些个人思考和总结

前言&#xff1a; 最近在公司做项目的时候&#xff0c;有一个业务场景就是同一张图片&#xff0c;在不同的位置上展示的效果是不一致的&#xff0c;其实理解起来也很简单&#xff0c;就以大家熟悉的微信头像而言&#xff0c;我们在正常使用的情况下&#xff0c;一个微信头像的大…

寻找多个项目的漏洞赏金实战,不同技术的详细实现

寻找多个项目的漏洞赏金实战,不同技术的详细实现。 破-解Slack App得到3500美金漏洞赏金 文章的核心要点如下: 漏洞发现:作者在Slack的安卓应用中发现了一个漏洞。这个漏洞是由于目录遍历,导致可以窃取密码。这个漏洞的重要性在于,它允许“跳跃”在账户之间,也就是说,你…

[kingbase锁等待问题分析]

参考文章:https://www.modb.pro/db/70021 概述 为了确保复杂的事务可以安全地同时运行&#xff0c;kingbase&#xff08;PostgreSQL&#xff09;提供了各种级别的锁来控制对各种数据对象的并发访问&#xff0c;使得对数据库关键部分的更改序列化。事务并发运行&#xff0c;直到…

Linux安全之AIDE系统入侵检测工具安装和使用

一、AIDE 系统入侵检测工具简介 AIDE&#xff0c;全称为Advanced Intrusion Detection Environment&#xff0c;是一个主要用于检测文件完整性的入侵检测工具。它能够构建一个指定文件的数据库&#xff0c;并使用aide.conf作为其配置文件。AIDE数据库能够保存文件的各种属性&am…

Django(十、中间件)

文章目录 一、中间件的介绍中间件有什么用中间件功能自定义中间中间件的顺序 一、中间件的介绍 中间件顾名思义&#xff0c;是介于request与response处理之间的一道处理过程&#xff0c;相对比较轻量级&#xff0c;并且在全局上改变django的输入与输出。因为改变的是全局&…

U盘启动制作工具Rufus

U盘启动制作工具Rufus 下载U盘启动制作工具Rufus&#xff0c;进入Rufus官网&#xff1a;http://rufus.ie/en/&#xff0c;打开之后往后滑动&#xff0c;找到download即可点击下载。 需要插入U盘 首先需要插入U盘&#xff0c;如果U盘有重要文件一定要备份&#xff0c;然后右键…

Grails 启动

Grails系列 Grails项目启动 文章目录 Grails系列Grails一、项目创建二、可能的问题1.依赖下载2.项目导入到idea失败3.项目导入到idea后运行报错 Grails Grails是一款基于Groovy语言的Web应用程序框架&#xff0c;它使用了许多流行的开源技术&#xff0c;如Spring Framework、…

内衣洗衣机怎么选?性价比高的小型洗衣机推荐

在机器解放了双手的时代中&#xff0c;洗衣机走进了千家万户&#xff0c;虽然在某种程度上缓解了人们手洗衣服的压力&#xff0c;但还是有不少人选择了人工手洗自己的内衣内裤&#xff0c;甚至连袜子都是手工洗的&#xff0c;这让人很是郁闷&#xff0c;倒不是说洗衣机不方便&a…