mybatis插件

news2024/12/28 20:17:17
Configuration组成

在这里插入图片描述

Mapper映射器

3个部分组成:

  • MappedStatement
    保存一个节点(select | insert | update | delete) ,包括我们配置的sql,,sql的id,,缓存信息,,resultMap,parameterType,resultType,languageDriver 等

  • SqlSource : 提供BoundSql对象的地方,是MappedStatement的一个属性

  • BoundSql : 建立sql和参数的地方

    三个常用属性:

    • sql : sql语句
    • parameterObject : 参数本身
    • parameterMappings : 是一个List,,由ParameterMapping组成,,这个对象会描述我们的参数,,比如:属性,名称,表达式,javaType,jdbcType,typeHandler等重要信息,,一个参数对应一个ParameterMapping
SqlSession下的四大对象
Executor执行器

调度StatementHandler,ParameterHandler,ResultSetHandler等来执行sql

mybatis存在三种执行器:

  • simple : 简易执行器,,默认的
  • reuse : 重用预处理语句
  • batch : 重用语句 和 批量更新

在配置文件中设置setting元素defaultExecutorType

StatementHandler 数据库会话器

使用数据库的Statement(PreparedStatement)执行操作
三种StatementHandler:

  • SimpleStatementHandler
  • PreparedStatementHandler
  • CallableStatementHandler

创建一个RoutingStatementHandler对象,,RoutingStatementHandler不是我们真实的服务对象,,他是通过适配模式找到对应的StatementHandler来执行的,,初始化RoutingStatementHandler对象的时候,他会根据上下文环境决定创建哪个StatementHandler对象

方法:

  • prepare() : 进行预编译sql语句,,同时设置一些基本运行的参数
  • parameterize() : 启用ParameterHandler设置参数,完成预编译
  • query() : 执行查询
ParameterHandler 参数处理器

对sql参数的处理,,对预编译语句进行参数设置

方法:

  • getParameterObject() : 返回参数对象
  • setParameters() : 设置预编译sql语句的参数

DefaultParameterHandler
从parameterObject对象中取出参数,使用typeHandler进行参数处理

ResultSetHandler 结果处理器

最后数据集ResultSet的处理
方法:

  • handleOutputParameters() : 处理存储过程输出参数
  • handlerResultSets() : 包装结果集
SqlSession运行总结

在这里插入图片描述

SqlSession执行过程:
SqlSession是通过 Executor 创建StatementHandler 来运行的,而StatementHandler要经过下面三个步骤:

  1. prepared : 预编译sql
  2. parameterize : 设置参数
  3. query/update : 执行sql

其中parameterize 是调用 ParameterHandler的方法去设置的,而且参数是根据类型处理器typeHandler处理。
query/update是通过resultHandler进行处理结果的封装,如果是update就返回整数,否则就通过typeHandler处理,,最后用 ObjectFactory 提供的规则组装对象,返回给调用者

插件

插件接口Interceptor:

  • intercept() : 直接覆盖你所拦截对象原有的方法,,
  • plugin() :给被拦截的对象生成一个代理对象 Plugin.wrap()
  • setProperties() : 配置所需要的参数
    在这里插入图片描述
    Plugin.wrap() : 生成这个对象的动态代理对象

调用方法的时候,会从最后一个代理对象的invoke方法运行到第一个代理对象的invoke方法,直至四大对象的真实方法

MetaObject 工具类使用

MetaObject这个工具类可以通过其他的技术手段读取或者修改这些重要对象的属性

方法:

  • SystemMetaObject.forObject() : 获取MetaObject
  • getValue() : 获取对象属性值
  • setValue() : 设置值
  public void test01(){
        User user = new User();
        MetaObject metaObject = SystemMetaObject.forObject(user);

        // 设置属性
        metaObject.setValue("userName","sb");
        metaObject.setValue("id",100L);

        // 设置list
        Role role = new Role();
        List<Role> roleList = Arrays.asList(role);
        metaObject.setValue("roleList",roleList);
        metaObject.setValue("roleList[0].roleName","test");

        System.out.println("user = " + user);
    }

引用:https://blog.csdn.net/Linging_24/article/details/126355031

插件开发

@Intercepts : 说明他是一个拦截器
@Signature : 注册拦截器签名的地方。。。。type是四大对象中的一个,method代表要拦截四大对象中的某一种接口的方法,,args表示参数

导包:

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.31</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.15</version>
    </dependency>

插件类:

@Intercepts(@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class,Integer.class}))
public class QueryLimitPlugin implements Interceptor {
    // 最大查询条数
    private int limit;
    // 数据库类型
    private String dbType;

    // 限制表中间别名,,避免表重名
    private static final String LMT_TABLE_NAME="limit_table_name_xxx";

//    private static final limit_
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拦截对象
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();


        MetaObject statementMetaObject = SystemMetaObject.forObject(statementHandler);

        // StatementHandler下面有一个 BoundSql对象 ,,
        // 获取原来的sql
        String sql = (String) statementMetaObject.getValue("boundSql.sql");

        String limitSql;
        // 数据库是mysql,并且这个sql没有被修改过
        if ("mysql".equals(dbType) && sql.indexOf(LMT_TABLE_NAME)==-1){
            limitSql = "select * from (  "+sql+" ) "+LMT_TABLE_NAME+" limit  "+limit;
            // 设置sql
            statementMetaObject.setValue("boundSql.sql",limitSql);
        }

        // 调度真实的StatementHandler的prepare()方法来完成sql预编译
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        // 返回代理对象
        return Plugin.wrap(target,this);
    }

    @Override
    public void setProperties(Properties properties) {
        this.dbType = properties.getProperty("dbType","mysql");
        this.limit = Integer.parseInt(properties.getProperty("limit","1"));
    }
}

配置文件:

<?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>
<!--    数据库-->
    <properties resource="jdbc.properties"/>

<!--    <settings>-->
<!--        <setting name="mapUnderscoreToCamelCase" value="true"/>-->
<!--    </settings>-->

    <settings>
<!--        autoMappingBehavior-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
<!--        <setting name="lazyLoadingEnabled" value="true"/>-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    <!--    定义别名 -->
    <typeAliases>
        <package name="com.cj.model"/>
    </typeAliases>

    <plugins>
        <plugin interceptor="com.cj.plugin.QueryLimitPlugin">
            <property name="dbtype" value="mysql"/>
            <property name="limit" value="1"/>
        </plugin>
<!--        <plugin interceptor="com.cj.plugin.MyPlugin">-->
<!--            <property name="dbType" value="mysql"/>-->
<!--        </plugin>-->
    </plugins>

    <!--    定义数据库信息,默认使用 development 数据库构建环境-->
    <environments default="development">
        <environment id="development">
            <!--            jdbc事务管理-->
            <transactionManager type="JDBC">
                <property name="autoCommit" value="true"/>
            </transactionManager>
            <!--            数据库信息-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql"/>
        <property name="SQL Server" value="sqlserver"/>
    </databaseIdProvider>

    <!--    定义映射器-->
    <mappers>
        <!--        sql和pojo 的映射规则定义,,mybatis解析这个xml,生成映射器 -->
<!--        <mapper resource="mapper/UserMapper.xml"/>-->

        <package name="com.cj.mapper"/>
    </mappers>
</configuration>

log4j.properties

log4j.rootLogger=DEBUG,stdout
log4j.logger.org.mybatis=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n

jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatisplus?serverTimezone=UTC
username=root
password=root

测试:

public interface UserMapper {
    @Select("select * from t_user")
    List<User> getAllUser();
}


    @Test
    public void test01() throws IOException {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis02.xml"));
        SqlSession sqlSession = factory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> allUser = userMapper.getAllUser();
        System.out.println("allUser = " + allUser);
    }

引入插件:

<plugin interceptor="com.cj.plugin.QueryLimitPlugin">
    <property name="dbtype" value="mysql"/>
    <property name="limit" value="1"/>
</plugin>
总结
  • 尽量不要用插件,插件生成的是层层代理对象的责任链模式,通过反射方法运行,性能不高
  • 插件的代码要考虑全面,特别是多个插件层层代理的时候,要保证逻辑的正确性

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

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

相关文章

Redis高并发锁(三)分布式锁

在很多情况下&#xff0c;你的数据库不支持事务&#xff0c;分布式部署也使得你无法去使用JVM锁&#xff0c;那么这种时候&#xff0c;你可以考虑用分布式锁 文章目录分布式锁1. 实现方式2. 特征3. 操作4. 代码改造5. 测试优化1. 递归改成循环2. 防止死锁3. 防误删4. LUA脚本 保…

Arduino code for RS-365PW 16120

Pictures These pictures are from Baidu Search. Picture 1: Installment Picture 2: Appearance Picture 3: Encoder of Motor Picture 4: Pins location and number Physical Specification Brand: Mabuchi Motor (万宝至电机)Type: RS-365PW 16120 Body length&#xff1…

学生抢课接口(高并发入门)

目录 使用Mysql 常规测试 张三测试 流程总结 redis优化 修改代码 测试 使用分布式锁 总结 使用Mysql 常规测试 原始代码: Override Transactional public ResponseResult selectCourse(SelectParmas selectParmas) {if (Objects.isNull(selectParmas)){return new …

【python游戏】新的一年快来变身兔兔战士打败獾守护兔兔吧~

前言 大家早好、午好、晚好吖 ❤ ~ 一只快乐兔&#xff0c; 来到快乐山&#xff0c;喝了快乐泉&#xff0c; 又到快乐殿&#xff0c;吃了快乐莲&#xff0c;遇到快乐仙&#xff0c; 听了快乐言&#xff1a;快乐很简单&#xff0c;快乐在身边&#xff0c;快乐无极限&#xff…

C++中STL的vector扩容机制

目录前言发生扩容扩容机制size()和capacity()reserve()和resize()前言 前阵子面试的时候&#xff0c;被问到往vector中插入一个数据可能会发生什么&#xff1f; 我答:可能会扩容; 为啥vector支持变长&#xff1f; 我答:它实在堆上动态申请内存&#xff0c;因此有自己的一套扩容…

Redis集群系列十 —— 集群伸缩之收缩

集群收缩原理 集群收缩就是让其中一些节点安全下线。 所谓的安全下线指的是让一个节点下线之前&#xff0c;把其负责的所有 slots 迁移到别的节点上&#xff0c;否则该节点下线后其负责的 slots 就没法继续提供服务了。 收缩流程如下&#xff1a; 需求 前面扩容完成后&…

字符串大小写转化,有序数组二分查找个人心得等若干内容

tips 1. 在电脑里面&#xff0c;任何一切字符&#xff0c;当一看到的时候&#xff0c;脑子里面就要把它转化成ACSII值。如while(0)&#xff0c;可以实现死循环。 2. 统计整形数组的长度不能用strlen()&#xff0c;别一天到晚用到底&#xff0c;strlen统计的是字符数组的长度 …

在wsl下开发T113的主线linux(1)-准备wsl开发环境

首先在win10或win11下安装wsl&#xff0c;选择wsl1或者wsl2都可以&#xff0c;wsl2的性能更高一些&#xff0c;wsl1的跨系统文件操作速度更快一些&#xff0c;我这里因为有一些工程在win文件系统下&#xff0c;所以选择了wsl1&#xff0c;发行版使用最新的Ubuntu 22.04.01 LTS。…

MySQL隐式转换

隐式转换概念 When an operator is used with operands of different types, type conversion occurs to make the operands compatible. Some conversions occur implicitly. 当运算符与不同类型的操作数一起使用时&#xff0c;将进行类型转换以使操作数兼容。某些转换是隐式发…

2022年年终总结---新方向,新期待

2022年行将结束&#xff0c;回首年初立下的flag&#xff1a; (1)完成OpenCoord版本升级&#xff0c;增加ITRF框架及历元转换、EGM2008查询功能&#xff1b; (2)完成多波束开源项目的数据读取和显示操作。 任务(1)已经完成了&#xff0c;任务&#xff08;2&#xff09;没有完成。…

力扣(LeetCode)2351. 第一个出现两次的字母(C++)

哈希集合 开哈希集合&#xff0c;遍历字符串&#xff0c;未出现的字母加入哈希集合&#xff0c;如果字母出现过&#xff0c;返回这个字母即可。 class Solution { public:char repeatedCharacter(string s) {unordered_set<char> S;for(auto &c:s)if(!S.count(c)) …

第二证券|72家公司接待机构过千,迈瑞医疗热度“断层领先”

2022年最终一个交易日&#xff0c;沪指以红盘收官&#xff0c;但年内A股商场震荡起伏&#xff0c;三大指数均收跌&#xff0c;其间&#xff0c;沪指全年下跌15%&#xff0c;创业板指跌近三成。 调研活动是出资者挖掘上市公司信息的重要来源&#xff0c;是洞悉商场主力资金意向的…

记录NCNN Yolov5部署华为鸿蒙系统踩过的坑

目录 踩坑一&#xff1a;Android Studio连接鸿蒙系统踩过的坑 踩坑二&#xff1a;配置Android studio环境 踩坑三&#xff1a;打开文件夹的位置 踩坑四&#xff1a;No toolchains found in the NDK toolchains folder for ABI with prefix: arm-linux-androideabi 总结 踩…

使用 Bitnami Helm 安装 Kafka

服务器端 K3S 上部署 Kafka Server Kafka 安装 &#x1f4da;️ Quote: charts/bitnami/kafka at master bitnami/charts (github.com) 输入如下命令添加 Helm 仓库&#xff1a; > helm repo add tkemarket https://market-tke.tencentcloudcr.com/chartrepo/opensource-…

LinuxShell注意事项

Linux 介绍 内存 虚拟内存 = 物理内存 + 交换空间 交换空间 = 交换空间 当用户访问某一个程序内存时,需要访问物理内存,而不是交换内存,如果物理内存没有,而交换内存有,则会将交换内存中的程序 加载进物理内存供用户使用,同样,当一个程序长期未访问,内核会将物理内…

【Mongoose笔记】Websocket 服务器

【Mongoose笔记】Websocket 服务器 简介 Mongoose 笔记系列用于记录学习 Mongoose 的一些内容。 Mongoose 是一个 C/C 的网络库。它为 TCP、UDP、HTTP、WebSocket、MQTT 实现了事件驱动的、非阻塞的 API。 项目地址&#xff1a; https://github.com/cesanta/mongoose学习 …

Chromium Embedded Framework(CEF)源码编译基于windows

1.打开维基百科CEF主页: Chromium Embedded Framework - Wikipedia 2.找到CEF仓库地址:chromiumembedded / cef — Bitbucket 打开CEF源码仓库: 点击 Wiki,然后在 Getting Started节,点击cef-project 向下拉浏览滚动条,可看到Setup章节

第三十二讲:神州交换机和路由器上分别实现QoS

QoS&#xff08;Quality of Service&#xff0c;服务品质保证&#xff09;是指一个网络能够利用各种各样的技术向选定的网络通信提供更好的服务的能力。QoS是服务品质保证&#xff0c;提供稳定、可预测的数据传送服务&#xff0c;来满足使用程序的要求&#xff0c;QoS不能产生新…

深入浅出闭包

目录 一、闭包概念 二、重载operator() 三、lambda表达式 3.1 lambda表达式介绍 3.2 lambda表达式语法 3.2.1 [capture-list]捕捉列表 3.2.2(parameters)&#xff1a;参数列表 3.2.3 mutable关键字 3.2.4 ->returntype&#xff1a;返回值类型 3.2.5 {statement}&a…

基于OpenSSL的安全Web Server实现

目录 一、实验目的 二、实验软硬件要求 三、实验预习 四、实验内容&#xff08;实验步骤、测试数据等&#xff09; 实验步骤 1编辑代码 2解决报错 3准备网页 五、实验体会&#xff08;遇到的问题及解决方法&#xff09; 六、服务器代码 七、测试网页代码 一、实验目…