Spring AOP 和 MyBatis插件 优化指数统计,代替MySQL触发器

Spring AOP 和 MyBatis插件 优化指数统计,代替MySQL触发器

  • 操作原理:在Spring AOP的环绕通知中调用MyBatis插件获取到具体的SQL和参数,在执行SQL之后,利用这些参数来新增“统计指数”。

    以下是具体实现步骤和示例代码:

实现步骤

  1. 定义MyBatis拦截器:首先使用MyBatis插件来拦截SQL的执行,获取到SQL语句和参数。
  2. 定义Spring AOP的环绕通知:在AOP切面中,使用环绕通知拦截特定的Mapper方法。
  3. 在环绕通知中调用MyBatis拦截器:在SQL执行前通过MyBatis拦截器获取SQL和参数,在SQL执行成功后执行额外的业务逻辑。

实现代码

1. 定义MyBatis拦截器获取SQL和参数

首先定义一个MyBatis拦截器,拦截并缓存最近执行的SQL和参数,这样可以在AOP通知中访问这些信息。

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.util.Properties;

@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class SqlInterceptor implements Interceptor {
    
    // 定义一个线程安全的变量用于存储最近的SQL和参数
    private static final ThreadLocal<String> currentSql = new ThreadLocal<>();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取StatementHandler并解析SQL语句
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        String sql = statementHandler.getBoundSql().getSql();
        
        // 缓存SQL
        currentSql.set(sql);

        // 执行原方法
        return invocation.proceed();
    }

    public static String getCurrentSql() {
        return currentSql.get();
    }
    
    // 移除数据,防止内存溢出
    public static void removeSql() {
        currentSql.remove();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {}
}

2. 配置拦截器

将拦截器添加到MyBatis配置中,使其生效。

<plugins>
    <plugin interceptor="com.example.interceptor.SqlInterceptor"/>
</plugins>

3. 定义Spring AOP的环绕通知

在Spring AOP切面中,使用环绕通知来拦截Mapper方法,获取SQL语句并在SQL执行后调用额外的业务逻辑。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SqlExecutionAopInterceptor {

    @Autowired
    private SomeOtherService someOtherService; // 依赖注入业务服务

    // 环绕通知拦截特定的Mapper方法,比如吊销铅笔
    @Around("execution(* com.example.mapper.SteelMapper.revokeSteel(..))")
    public Object aroundExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;

        try {
            System.out.println("开始执行SQL操作...");
            
            // 在SQL执行之前,通过拦截器获取SQL语句
            String sql = SqlInterceptor.getCurrentSql();
            SqlInterceptor.removeSql();
            System.out.println("即将执行的SQL语句:" + sql);

            // 执行Mapper方法,获取SQL执行结果
            result = joinPoint.proceed();

            // 检查SQL执行结果,执行后续业务逻辑
            if (result != null && result instanceof Integer && (Integer) result > 0) {
                System.out.println("SQL执行成功,执行额外操作...");
                
                // 调用业务方法,传入所需的SQL参数(根据需求从方法参数中获取)
                someOtherService.addRevokeCount(sql);
            } else {
                System.out.println("SQL未成功执行,未执行额外操作");
            }

        } catch (Exception e) {
            System.out.println("SQL执行过程中出现异常:" + e.getMessage());
            throw e; // 抛出异常,确保事务一致性
        }

        return result;
    }
}

4. 定义业务服务类并实现“新增统计指数”

在业务服务SomeOtherService中,实现“新增统计指数”的逻辑。你可以利用SQL中包含的参数来执行额外的更新逻辑。

import org.springframework.stereotype.Service;

@Service
public class SomeOtherService {

    public void addRevokeCount(String sql) {
        // 解析SQL获取必要的参数(根据实际业务情况解析SQL中的参数)
        // 例如提取铅笔ID等数据
        System.out.println("新增统计指数,SQL信息:" + sql);
        
        // 在这里调用Mapper方法,执行更新操作
    }
}

总结

  • MyBatis拦截器用于捕获即将执行的SQL,将SQL语句暂存至ThreadLocal中。
  • 环绕通知在SQL执行前后分别获取SQL和执行结果,确保在SQL执行成功后执行附加业务逻辑。
  • 业务方法调用中可以使用SQL语句的内容来执行特定的操作。

这样可以确保每次SQL执行前后在Spring AOP和MyBatis拦截器的配合下获取并使用SQL语句,完成业务需求。

SqlInterceptor 执行 invocation.proceed();然后 SqlExecutionAopInterceptor 又执行joinPoint.proceed(),会冲突吗,也就是导致SQL反复执行吗?

在这个实现方案中,SqlInterceptorSqlExecutionAopInterceptorproceed() 方法的调用不会导致 SQL 反复执行,因为它们在不同的层次和时间点生效,并且具有不同的职责。

具体说明

  1. SqlInterceptor(MyBatis 拦截器)

    • 它是 MyBatis 插件,拦截 MyBatis 在生成并准备执行 SQL 语句时的行为。
    • 调用 invocation.proceed() 是为了让 MyBatis 继续执行原本的逻辑,否则拦截器会阻止原方法的执行,导致 SQL 无法被正常执行。
    • 此拦截器仅用于捕获 SQL 语句及其参数,不会实际改变 SQL 执行流程或执行 SQL。
  2. SqlExecutionAopInterceptor(Spring AOP 拦截器)

    • 它是 Spring AOP 切面,用于拦截特定的 Java 方法调用,例如 DAO 层的方法。
    • 调用 joinPoint.proceed() 是为了继续执行被拦截的方法,如果不调用 proceed(),原方法逻辑将不会被执行。
    • 它负责在方法执行前后添加逻辑,比如在执行后根据执行结果进行附加操作。

是否会导致 SQL 反复执行?

不会。SqlInterceptorSqlExecutionAopInterceptor 都是拦截器,但它们作用在不同层次上:

  • SqlInterceptor 仅拦截 MyBatis 内部的 SQL 执行操作,不涉及具体的 Java 方法调用。
  • SqlExecutionAopInterceptor 仅拦截由 Spring 管理的 DAO 层方法调用,与 MyBatis 拦截器是独立的,执行 joinPoint.proceed() 是为了确保 DAO 方法继续执行。

两者结合使用时:

  • SqlExecutionAopInterceptor 拦截方法时会调用 joinPoint.proceed() 执行 DAO 方法,这会触发 MyBatis 执行 SQL。
  • SqlInterceptor 在 MyBatis 执行 SQL 时捕获 SQL 语句并保存。
  • 最终,SQL 只会被执行一次,不会重复执行。

总结

SqlInterceptorSqlExecutionAopInterceptorproceed() 方法调用不会冲突,也不会导致 SQL 反复执行,因为它们在不同的层次和作用域中运行。如果实现中没有其他逻辑错误,整个执行链条会按照预期进行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】类与对象的基础概念

目录&#xff1a; 一、inline 二、类与对象基础 &#xff08;一&#xff09;类的定义 &#xff08;二&#xff09;访问限定符 &#xff08;三&#xff09;类域 &#xff08;四&#xff09;实例化概念 正文 一、inline 在C语言的学习过程中&#xff0c;大家肯定了解过宏这个概…

matlab实现主成分分析方法图像压缩和传输重建

原创 风一样的航哥 航哥小站 2024年11月12日 15:23 江苏 为了研究图像的渐进式传输技术&#xff0c;前文提到过小波变换&#xff0c;但是发现小波变换非常适合传输缩略图&#xff0c;实现渐进式传输每次传输的数据量不一样&#xff0c;这是因为每次变换之后低频成分大约是上一…

python成长技能之网络编程

文章目录 一、初识Socket1.1 什么是 Socket?1.2 socket的基本操作1.3 socket常用函数 二、基于UDP实现客户端与服务端通信三、基于TCP实现客户端与服务端通信四、使用requests模块发送http请求 一、初识Socket 1.1 什么是 Socket? Socket又称"套接字"&#xff0c;…

ROM修改进阶教程------安卓14 安卓15去除app签名验证的几种操作步骤 详细图文解析

在安卓14 安卓15的固件中。如果修改了系统级别的app。那么就会触发安卓14 15的应用签名验证。要么会导致修改的固件会进不去系统,或者进入系统有bug。博文将从几方面来解析去除安卓14 15应用签名验证的几种方法。 💝💝💝通过博文了解: 1💝💝💝-----安卓14去除…

[Docker#6] 镜像 | 常用命令 | 迁移镜像 | 压缩与共享

目录 Docker 镜像是什么 生活案例 为什么需要镜像 镜像命令详解 实验 1.一些操作 1. 遍历查看镜像 2. 查看镜像仓库在本地的存储信息 进入镜像存储目录 查看 repositories.json 文件 3. 镜像过滤 4. 下载镜像时的分层 实战一&#xff1a;离线迁移镜像 实战二&…

「QT」几何数据类 之 QVector3d 三维向量类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

人工智能(AI)对于电商行业的变革和意义

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/402a907e12694df5a34f8f266385f3d2.png#pic_center> &#x1f393;作者简介&#xff1a;全栈领域优质创作者 &#x1f310;个人主页&#xff1a;百锦再新空间代码工作室 &#x1f4de;工作室&#xff1a;新空间代…

物联网设备研究——分配推理负载的联合学习方法

概述 物联网&#xff08;IoT&#xff09;的最新发展导致人工智能模型被嵌入到传感器和智能手机等终端设备中。这些模型是根据每个设备的存储容量和计算能力定制的&#xff0c;但重点是在终端侧进行本地推理&#xff0c;以降低通信成本和延迟。 然而&#xff0c;与部署在边缘服…

CentOS Stream 9设置静态IP

CentOS Stream 9设置静态IP CentOS Stream 9作为CentOS Stream发行版的下一个主要版本&#xff0c;已经发布有一段时间&#xff0c;但与目前广泛使用的CentOS7有较大区别。安装试用Stream 9的过程中&#xff0c;就发现设置静态IP的方式和CentOS7/8差别较大&#xff0c;在此记录…

【嵌入式】ESP32开发(一)ESP-IDF概述

文章目录 1 前言2 IDF环境配置3 在VS Code中使用IDF3.1 使用ESP-IDF例程3.2 底部按钮的作用【重要!】3.3 高级用法4 ESP-IDF框架分析5 从零开始创建一个项目5.1 组件(component)6 主要参考资料7 遇到的一些问题与解决办法8 对于ESP-IDF开发的一些感受1 前言 对于ESP32的开发…

基于Multisim水箱水位控制系统仿真电路(含仿真和报告)

【全套资料.zip】水箱水位控制系统仿真电路Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.在水箱内的不同高度安装3根金属棒&#xff0c;以感知水位变化情况&#xff0c; 液位分1&…

解读Nature:Larger and more instructable language models become less reliable

目录 Larger and more instructable language models become less reliable 核心描述 核心原理 创新点 举例说明 大模型训练,微调建议 Larger and more instructable language models become less reliable 这篇论文的核心在于对大型语言模型(LLMs)的可靠性进行了深入…

zabbix监控端界面时间与服务器时间不对应

1. 修改系统时间 # tzselect Please select a continent, ocean, "coord", or "TZ".1) Africa2) Americas3) Antarctica4) Asia5) Atlantic Ocean6) Australia7) Europe8) Indian Ocean9) Pacific Ocean 10) coord - I want to use geographical coordina…

ubuntu20.04安装FLIR灰点相机BFS-PGE-16S2C-CS的ROS驱动

一、Spinnaker 安装 1.1Spinnaker 下载 下载地址为&#xff1a; https://www.teledynevisionsolutions.com/support/support-center/software-firmware-downloads/iis/spinnaker-sdk-download/spinnaker-sdk–download-files/?pnSpinnakerSDK&vnSpinnakerSDK 在上述地址中…

Windows配置JDK

1、解压 下载以后解压&#xff0c;放在一个没有中文路径和没有空格的目录&#xff0c;如下图&#xff1a; 2、配置Java环境 1&#xff09;、点击左下角windows图标&#xff0c;输入huanjing&#xff08;或者path&#xff09;&#xff0c;打开环境变量配置 如图&#xff1a; …

Unity教程(十八)战斗系统 攻击逻辑

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

HCIP-HarmonyOS Application Developer 习题(二十三)

1、&#xff08;多选&#xff09;端云一体化已经集成以下哪些服务SDK。 A、云函数 B、云数据库 C、云存储 D、云托管 答案&#xff1a;AB 分析&#xff1a;云开发即为应用开发云侧工程&#xff0c;目前包含云函数与云数据库工程。 2、&#xff08;多选&#xff09;Entry下的m…

图数据库 | 5、图数据库三大组件之一 之 图计算 (下)

书接上文&#xff1a;图数据库 | 4、图数据库三大组件之一 ——图计算 &#xff08;上&#xff09;-CSDN博客 结合计算效率来评估与设计图计算所需的数据结构。 存储低效性或许是相邻矩阵或关联矩阵等数据结构的最大缺点&#xff0c;尽管它有着O(1)的访问时间复杂度。例如通过…

Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别

目录 一、概念 1、纹理过滤 2、邻近过滤 3、线性过滤 二、邻近过滤和线性过滤的区别 三、源码下载 一、概念 1、纹理过滤 当纹理被应用到三维物体上时&#xff0c;随着物体表面的形状和相机视角的变化&#xff0c;会导致纹理在渲染过程中出现一些问题&#xff0c;如锯齿…

【java】java通过s3访问ceph报错

1.报错信息、背景 工作中起了几个访问ceph的服务pod节点&#xff0c;一段时间后1个节点一直报错Unable to execute HTTP request: Timeout waiting for connection from pool&#xff0c;详细i信息如下图片&#xff0c;有且仅有1个节点报错&#xff0c;其他节点访问正常。看日志…