MyBatis拦截器使用方法

前言

MyBatis拦截器可以做的工作:SQL修改分页操作数据过滤SQL执行时间性能监控等。

1. 基础介绍

1.1. 核心对象

MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:

        ·Configuration:初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如插件,映射器,ObjectFactorytypeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中。
        ·SqlSessionFactorySqlSession工厂。
        ·SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要的数据库增删改查功能。
        ·ExecutorMyBatis的内部执行器,它负责调用StatementHandler操作数据库,并把结果集通过ResultSetHandler进行自动映射,另外,它还处理二级缓存的操作。
        ·StatementHandlerMyBatis直接在数据库执行SQL脚本的对象。另外它也实现了MyBatis的一级缓存。
        ·ParameterHandler:负责将用户传递的参数转换成JDBC Statement所需要的参数。是MyBatis实现SQL入参设置的对象。
        ·ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合。是MyBatisResultSet集合映射成POJO的接口对象。
        ·TypeHandler:负责Java数据类型和JDBC数据类型之间的映射和转换。
        ·MappedStatementMappedStatement维护了一条<select|update|delete|insert>节点的封装。
        ·SqlSource :负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回。
        ·BoundSql:表示动态生成的SQL语句以及相应的参数信息。

1.2. 执行过程

2. 实现步骤

       1.写一个实现org.apache.ibatis.plugin.Interceptor接口的拦截器类,并实现其中的方法。

        2.添加@Intercepts注解,写上需要拦截的对象和方法,以及方法参数。
        3.Spring项目注意添加@Component注解即可,使其成为Spring管理的一个Bean

2.1. 添加注解
MyBatis拦截器默认可以拦截的类型只有四种,即四种接口类型ExecutorStatementHandlerParameterHandlerResultSetHandler。对于我们的自定义拦截器必须使用MyBatis提供的@Intercepts注解来指明我们要拦截的是四种类型中的哪一种接口。

@Signature注解的参数:

@Intercepts({
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
    @Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
    @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
2.1.1. type

MyBatis拦截器默认会按顺序拦截以下的四个接口中的所有方法:

org.apache.ibatis.executor.Executor  //拦截执行器方法
org.apache.ibatis.executor.statement.StatementHandler  //拦截SQL语法构建处理
org.apache.ibatis.executor.parameter.ParameterHandler  //拦截参数处理
org.apache.ibatis.executor.resultset.ResultSetHandler  //拦截结果集处理

具体是拦截这四个接口对应的实现类:

org.apache.ibatis.executor.CachingExecutor
org.apache.ibatis.executor.statement.RoutingStatementHandler
org.apache.ibatis.scripting.defaults.DefaultParameterHandler
org.apache.ibatis.executor.resultset.DefaultResultSetHandler

2.1.2. method

这个可以根据MyBatis源码了解下。

2.1.3. args

根据参数类型区分重载的方法。

2.2. 方法实现
2.2.1. intercept

进行拦截的时候要执行的方法。该方法参数Invocation类中有三个字段:

  private final Object target;
  private final Method method;
  private final Object[] args;

可通过这三个字段分别获取下面的信息:

Object target = invocation.getTarget();//被代理对象
Method method = invocation.getMethod();//代理方法
Object[] args = invocation.getArgs();//方法参数

2.2.2. plugin
插件用于封装目标对象的,通过该方法我们可以返回目标对象本身,也可以返回一个它的代理,可以决定是否要进行拦截进而决定要返回一个什么样的目标对象,官方提供了示例:return Plugin.wrap(target, this);,可以在这个方法中提前进行拦截对象类型判断,提高性能:

    @Override
    public Object plugin(Object target) {
        //只对要拦截的对象生成代理
        if(target instanceof StatementHandler){
            //调用插件
            return Plugin.wrap(target, this);
        }
        return target;
    }

MyBatis拦截器用到责任链模式+动态代理+反射机制;
所有可能被拦截的处理类都会生成一个代理类,如果有N个拦截器,就会有N个代理,层层生成动态代理是比较耗性能的。而且虽然能指定插件拦截的位置,但这个是在执行方法时利用反射动态判断的,初始化的时候就是简单的把拦截器插入到了所有可以拦截的地方。所以尽量不要编写不必要的拦截器。另外我们可以在调用插件的地方添加判断,只要是当前拦截器拦截的对象才进行调用,否则直接返回目标对象本身,这样可以减少反射判断的次数,提高性能。

2.2.3. setProperties
如果我们拦截器需要用到一些变量参数,而且这个参数是支持可配置的,类似Spring中的@Value("${}")从application.properties文件获取自定义变量属性,这个时候我们就可以使用这个方法。

(1)在application.properties文件中添加配置:

mybatis.config-location=classpath:mybatis-config.xml

(2)在resources目录下添加mybatis-config.xml配置文件,并添加插件和属性配置。添加完需要注意去掉自定义MyBatis拦截器上的@Component注解,否则该拦截器相当于注册了两个,会执行两遍拦截方法。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.example.demo.mapper.plugin.MyPlugin">
            <property name="key1" value="value1"/>
            <property name="key2" value="value2"/>
            <property name="key3" value="value3"/>
        </plugin>
    </plugins>
</configuration>

(3)在拦截器插件的setProperties方法中进行。这些自定义属性参数会在项目启动的时候被加载。

    @Override
    public void setProperties(Properties properties) {
        System.out.println("key1=" + properties.getProperty("key1"));
        System.out.println("key2=" + properties.getProperty("key2"));
        System.out.println("key3=" + properties.getProperty("key3"));
    }

3. 代码示例

package com.example.demo.mapper.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Properties;

@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {

    Properties properties = null;

    /**
     * 拦截方法逻辑
     * 这里主要是通过反射去获取要执行的SQL相关信息,然后进行操作
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();//被代理对象
        Method method = invocation.getMethod();//代理方法
        Object[] args = invocation.getArgs();//方法参数
        // do something ...... 方法拦截前执行代码块
        Object result = invocation.proceed();
        // do something .......方法拦截后执行代码块
        return result;
    }

    /**
     * 生成MyBatis拦截器代理对象
     */
    @Override
    public Object plugin(Object target) {
        if(target instanceof StatementHandler){
            //调用插件
            return Plugin.wrap(target, this);
        }
        return target;
    }

    /**
     * 设置插件属性(直接通过Spring的方式获取属性,所以这个方法一般也用不到)
     * 项目启动的时候数据就会被加载
     */
    @Override
    public void setProperties(Properties properties) {
        //赋值成员变量,在其他方法使用。
        this.properties = properties;
    }
}

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

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

相关文章

OpenStack所支持的虚拟化技术和KVM、Xen、Hyer-V、QEMU、Libvirt说明

OpenStack所支持的虚拟化技术主要包括以下几种&#xff1a; KVM (Kernel-based Virtual Machine): 基于Linux内核的虚拟化技术。在Linux内核中添加一个虚拟化模块来实现虚拟机的运行。是OpenStack用户使用较多的虚拟化技术&#xff0c;支持OpenStack的所有特性。通过QEMU模拟器…

【NoSQL数据库】Redis——哨兵模式

Redis——哨兵模式 Redis哨兵 Redis——哨兵模式1.什么是哨兵机制&#xff08;Redis Sentinel&#xff09;1.1 哨兵的作用 2.哨兵的运行机制3.故障处理redis常见问题汇总1、redis缓存击穿是什么&#xff1f;如何解决&#xff1f;2、redis缓存穿透是什么&#xff1f;如何解决&am…

详解!Python怎么配置环境变量

详解&#xff01;Python怎么配置环境变量 许多刚开始学习编程的初学者在 python的安装上会抱有一定的疑惑&#xff0c;为什么明明已经安装好了 python 环境&#xff0c;但并不能运行python 代码&#xff0c;这是因为 python 的安装过程中还有一步环境变量的配置&#xff0c;接…

微信“对方正在输入”背后的小心思:保持隐秘感,享受宁静的交流

微信&#xff0c;这个伴随我们起居、工作的超级应用&#xff0c;不仅仅是一款聊天软件&#xff0c;它几乎成为了我们社交生活的一部分。它的便捷&#xff0c;让我们的日常沟通如鱼得水。然而&#xff0c;在这个几乎完美的社交工具中&#xff0c;有一个功能&#xff0c;让不少人…

CSS真题合集(二)

CSS真题合集&#xff08;二&#xff09; 11. css3新增特性12. css3动画12.1 关键帧动画 (keyframes)12.2 animation12.3 transition12.4 transform 13. grid网格布局13.1 使用display: grid或display: inline-grid的HTML元素。13.2 定义网格13.3 13.4 自动填充和自动放置13.4 对…

信号发生器如何将频率调大,步尽值改成10

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

PPT文件损坏且无法读取怎样修复?文档损坏修复方法推荐

PPT文件已经成为工作汇报、商务演示、学术交流以及教学培训中最常用到的文件&#xff0c;随着文件数量的增多和存储设备的频繁使用&#xff0c;我们有时会遇到PPT文件损坏无法打开的情况&#xff0c;这无疑给工作和学习带来了极大的困扰。 PPT文件损坏的原因可能多种多样&#…

FreeRTOS手表项目多级菜单的实现

一、首先介绍一下智能手表项目的背景&#xff1a; 如图&#xff0c;关注焦点是任务&#xff1a; 1、在一个确定时刻&#xff0c;在那一圈任务中&#xff08;写有只有一个任务解挂&#xff09;只有一个任务处在运行&#xff0c;界面显示的是该任务应该显示的内容&#xff1b; …

韩国Neowine推出第三代强加密芯片ALPU-CV

推出第三代加密芯片&#xff1b;是ALPU系列中的高端IC&#xff1b;是一款高性能车规级加密芯片&#xff1b;其加密性更强、低耗电、体积小&#xff1b;使得防复制、防抄袭板子的加密性能大大提升&#xff0c;该芯片通过《AEC-Q100》认证&#xff0c;目前已经在国产前装车辆配件…

代理记账公司哪家好,深度剖析与选择指南

代理记账&#xff0c;作为企业会计管理和运营的重要环节&#xff0c;已经逐渐被越来越多的企业所重视&#xff0c;在众多的代理记账公司中&#xff0c;如何选择一家专业、高效且值得信赖的代理记账机构呢&#xff1f;以下是一些深度解析和推荐。 公司的规模 规模较大的代理记账…

docker实战命令大全

文章目录 1 环境准备1.1 移除旧版本Docker1.2安装工具包1.3配置docker yum源 2 安装最新docker2.1 设置开机自启docker2.2配置加速器 3 实操-镜像3.1搜索镜像3.2下载镜像3.3查看镜像3.4 删除镜像 4 实操-容器4.1运行nginx容器4.2 查看容器4.3启动容器4.5关闭容器4.6查看容器日志…

Linux中Apache网站基于Http服务的访问限制(基于地址/用户)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f468;‍&#x1f4bb;Linux高级管理专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月3日11点44分 &#x1f004;️文章质量&#xff1a;95分 为了更好地控制对网站资源的访问&#xff0c;可…

基于SSM+Jsp的高校二手交易平台

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

前端怎么预览pdf

1.背景 后台返回了一个在线的pdf地址&#xff0c;需要我这边去做一个pdf的预览&#xff08;需求1&#xff09;&#xff0c;并且支持配置是否可以下载&#xff08;需求2&#xff09;&#xff0c;需要在当前页就能预览&#xff08;需求3&#xff09;。之前我写过一篇预览pdf的文…

ant design的upload组件踩坑记录

antd版本 v4.17.0 1.自定义了onpreview和onchange事件&#xff0c;上传文件后&#xff0c;文件显示有preview的icon但是被禁用&#xff0c;无法调用onpreview事件。 问题展现&#xff1a; 苦苦查找原因&#xff0c;问题出在了这里&#xff0c;当文件没有url的时候&#xff0c…

基于FPGA的图像一维FFT变换IFFT逆变换verilog实现,包含tb测试文件和MATLAB辅助验证

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 fpga仿真结果 matlab调用FPGA的仿真结果进行图像显示 2.算法运行软件版本 vivado2019.2 matlab2022a 3.部分核心程序 ......................…

mac系统内存占用过高怎么办 优化电脑内存的方法系统加速

不少Mac用户都对mac系统内存占用过高非常头痛&#xff0c;不过这是mac在使用过程中一个很常见的问题&#xff0c;它会影响用户的操作体验&#xff0c;导致系统运行速度缓慢&#xff0c;甚至出现明显的卡顿现象。面对mac系统内存占用过高怎么办这个问题&#xff0c;其实很好解决…

C#操作MySQL从入门到精通(11)——对查询数据使用正则表达式过滤

前言 对于之前提到的使用匹配、比较、通配符等过滤方式能解决大部分的项目问题,但是有时候也会遇到一些比较复杂的过滤需求,这时候就需要正则表达式来实现了,正则表达式使用regexp这个关键字来实现。 本次测试的数据库表的内容如下: 1、基本字符匹配(包含某些字符) 匹…

git一次提交多个项目之windows

方案1:【快速】单个/多个项目提交到一个已有地址 步骤: 1,在git仓库,创建新的地址 2,在代码所在文件夹,编辑脚本 2.1,获得所有文件名:编写bat脚本,获得所有文件名称【非必须】; dir *.* /b/s>test.txt 获取所有文件之后,复制对应的文件名; 2.2,编写bat脚…

如何做好电子内窥镜的网络安全管理?

电子内窥镜作为一种常用的医疗器械&#xff0c;其网络安全管理对于保护患者隐私和医疗数据的安全至关重要。以下是一些基本原则和步骤&#xff0c;用于确保电子内窥镜的网络安全&#xff1a; 1. 数据加密 为了防止数据泄露&#xff0c;电子内窥镜在传输患者图像数据时应采取有…