扩展BaseMapper类 - 详解

news/2025/10/28 19:58:41/文章来源:https://www.cnblogs.com/yangykaifa/p/19172616

扩展mybatis-plus的BaseMapper类

  • insertBatch
  • insertIfNotExists

mp的BaseMapper只提供了简单的增删改查方法,一些复杂点的操作没有提供,或是在IService类中提供。如果想要直接通过mapper类调用这些方法,可以通过扩展BaseMapper来使其获取新的功能。

insertBatch

扩展一个批量插入insertBatch的方法。

  1. 定义SqlInjector类,扩展功能
public class ExpandSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {List<AbstractMethod> methodList = super.getMethodList(mapperClass);methodList.add(new InsertBatchMethod());methodList.add(new InsertIfNotExistsMethod());return methodList;}/*** 批量插入方法*/public static class InsertBatchMethod extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {String sql = "<script>INSERT INTO %s (%s) VALUES %s";List<String> columnList = new ArrayList<>();List<String> propertyList = new ArrayList<>();if (tableInfo.havePK() && !AUTO.equals(tableInfo.getIdType())) {columnList.add(tableInfo.getKeyColumn());propertyList.add(tableInfo.getKeyProperty());}// getFiledList等方法获取的内容会自动根据@TableField相关配置而改变for (TableFieldInfo fieldInfo : tableInfo.getFieldList()) {columnList.add(fieldInfo.getColumn());propertyList.add(fieldInfo.getProperty());}String columns = String.join(",", columnList);String values = "<foreach collection='list' item='item' separator=','>" +"(#{item." + String.join("},#{item.", propertyList) + "})" +"</foreach></script>";String sqlResult = String.format(sql, tableInfo.getTableName(), columns, values);SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);return getMappedStatement(this::addInsertMappedStatement, mapperClass, "insertBatch", modelClass, tableInfo, sqlSource, "");}}private static MappedStatement getMappedStatement(MappedStatementMethod method, Class<?> mapperClass, String id, Class<?> modelClass, TableInfo tableInfo, SqlSource sqlSource, String prefix) {// 根据@TableId注解自动设置KeyGeneratorKeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; // 默认值String keyColumn = null;String keyProperty = null;// 如果表有主键字段if (tableInfo.havePK()) {keyColumn = tableInfo.getKeyColumn();keyProperty = prefix + tableInfo.getKeyProperty();// 根据主键类型设置,INPUT、NONE:NoKeyGenerator,ASSIGN_ID, ASSIGN_UUID等策略,Java层面生成,不需要数据库生成if (AUTO.equals(tableInfo.getIdType())) {keyGenerator = Jdbc3KeyGenerator.INSTANCE;}}// 这里的keyGenerator与实际sql语句无关,是否插入id取决你构造的sql语句return method.accept(mapperClass, modelClass, id, sqlSource, keyGenerator, keyProperty, keyColumn);}@FunctionalInterfacepublic interface MappedStatementMethod {MappedStatement accept(Class<?> mapperClass, Class<?> parameterType, String id, SqlSource sqlSource, KeyGenerator keyGenerator, String keyProperty, String keyColumn);}}
  1. 配置SqlInjector:在mp的配置类中(也可以通过yml文件配置)
@Bean
public ExpandSqlInjector expandSqlInjector() {
return new ExpandSqlInjector();
}
  1. 具体mapper类加上insertBatch方法;或定义一个新的BaseMapper,让其继承BaseMapper(推荐后者,可以统一配置)

实际通过前面二步,生成的BaseMapper代理类已经有了扩展的方法,这一步了是为了让接口也拥有扩展方法。

public interface AppMapper<T> extends BaseMapper<T> {/*** 批量插入* @param list 实体列表* @return 插入条数*/int insertBatch(List<T> list);}

insertIfNotExists

扩展一个不存在则插入insertIfNotExists的方法。

  1. ExpandSqlInjector类中添加以下内容
/**
* 如果满足条件的记录不存在才插入
*/
public static class InsertIfNotExistsMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {// 动态生成 SQLString sql = "<script>INSERT INTO %s (%s) " +"SELECT %s FROM dual " +"WHERE NOT EXISTS (" +"   SELECT 1 FROM %s ${ew.customSqlSegment}" +")</script>";// 1. 插入的字段列表(会自动加上if标签,根据类型添加相关的非空判断,最后一个字段会多个逗号)String insertColumns = tableInfo.getAllInsertSqlColumnMaybeIf("entity.");insertColumns = SqlScriptUtils.convertTrim(insertColumns, null, null, null, ",");// 2. 插入的值(会自动加上if标签,根据类型添加相关的非空判断,最后一个值会多个逗号)String insertValues = tableInfo.getAllInsertSqlPropertyMaybeIf("entity.");insertValues = SqlScriptUtils.convertTrim(insertValues, null, null, null, ",");String tableName = tableInfo.getTableName();String sqlResult = String.format(sql, tableName, insertColumns, insertValues, tableName);SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);return getMappedStatement(this::addInsertMappedStatement, mapperClass, "insertIfNotExists", modelClass, tableInfo, sqlSource, "entity.");}}
  1. AppMapper类里添加以下内容:
/**
* 插入,如果满足指定条件的记录已存在则忽略
* @param entity 插入的实体类实例
* @param ew 条件对象
*/
int insertIfNotExists(@Param("entity") T entity, @Param(WRAPPER) Wrapper<T> ew);

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

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

相关文章

《程序员修炼之道:从小工到专家》前五分之二观后感

读完《程序员修炼之道:从小工到专家》前五分之二的内容,我对“程序员如何成长”有了更清晰的认知。书中开篇便强调“职业主义”,打破了我对“码农”的刻板印象——程序员不应只是被动执行需求的工具人,而应像匠人般…

矩阵快速幂章节笔记(这里主要介绍的是我的错题)

矩阵加速的递推 1.1维k阶 f(n)=f(n-1)+f(n-2)+f(n-i)可以添加系数 那么矩阵的第一列就是系数了,其它用未知数,然后计算。注意start数组,就是开始的数组是倒着来的,请看代码(斐波那契) 2.k维1阶 dp[i][j]=dp[i-…

实验二 现代C++编程初体验

任务一: 代码:#pragma once#include <string>// 类T: 声明 class T { // 对象属性、方法 public:T(int x = 0, int y = 0); // 普通构造函数T(const T &t); // 复制构造函数T(T &&t); //…

P5322 [BJOI2019] 排兵布阵

P5322 [BJOI2019] 排兵布阵 题解题目传送门 博客传送门 我们浏览一遍测试点,发现了一个 \(s=1\) 的特殊性质。先考虑这一性质。 \(s=1\)特殊性质 如果我们当前第 \(i\) 座城市的兵力数量足够时,添加兵力显然不优。而…

题解:P9292 [ROI 2018] Robomarathon

题目传送门 题目大意: 有 \(N\) 名机器人选手参加马拉松,选手编号为 \(1 \dots N\),分道编号也为 \(1 \dots N\)。选手 \(i\) 占据分道 \(i\),跑完全程需要 \(a_i\) 秒。设 \(S \subseteq \{1, 2, \dots, N\}\) 表…

[题解]P5322 [BJOI2019] 排兵布阵

P5322 [BJOI2019] 排兵布阵 我们可以预处理出第 \(i\) 个城堡分配 \(j\) 的兵力能获得多少的得分,记为 \(w[i][j]\)。 则每一个 \(w[i]\) 都是一个泛化物品,即价值(\(w[i][j]\))随着分配体积(\(j\))变化的物品。…

申威服务器安装Nacos 2.0.3 RPM包详细步骤(Kylin V10 sw_64架构)​附安装包

申威服务器安装Nacos 2.0.3 RPM包详细步骤(Kylin V10 sw_64架构)​附安装包​ Nacos 2.0.3-1.ky10.sw_64.rpm​ 是专为 ​申威(SW)架构​ 处理器,并运行 ​中标麒麟操作系统 Kylin V10(64位)​​ 的服务器环境定…

ZKY精选冲刺省选国赛仿真训练题

求和 QOJ - 9902 解题思路 代码实现点击查看代码Bridges AtCoder - arc143_d 解题思路 代码实现点击查看代码龙门考古 UniversalOJ - 840 解题思路 代码实现点击查看代码Discrete Centrifugal Jumps CodeForces - 1407…

MySQL 查询与更新语句执行过程深度解析:从原理到实践​ - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

ZKY精选冲刺省选国赛技巧训练题

Discrete Centrifugal Jumps CodeForces - 1407D 解题思路 代码实现点击查看代码序列妙妙值 UniversalOJ - 549 解题思路 代码实现点击查看代码Constrained Sums AtCoder - abc277_h 解题思路 代码实现点击查看代码ag…

逆向基础--编码(001)

逆向基础--编码(001)一.位与字节比特(Bit):1比特就是1位,每个0或1就是一个位,位是数据存储的最小单位。位是二进制表示,8位二进制是一个字节。 8位二进制(就是8个比特)最大:11111111字节(Byte):字节是通过网…

20251027 - 倍增 ST表

前言: 怎么标题改来改去的? 概念 因为每一个整数都可以转换成对应的二进制,所以可以表示成 \(a_0 \times 2^0 + a_1 \times 2 ^ 1 + a_2 \times 2 ^ 2 + a_{len} \times 2 ^ {len}\)。 因此,对于求跳 \(x\) 步后的…

周康阳精选冲刺省选国赛思维训练题

agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long C…

Luogu P7913 [CSP-S 2021] 廊桥分配 题解 [ 绿 ] [ 贪心 ] [ 前缀和 ] [ STL ]

廊桥分配 笑点解析:VP 的时候想这题想了 20min,比想 T3 的时间长。 关键结论:在不考虑廊桥限制的情况下,给每个飞机分配一个最小的廊桥编号。当最终廊桥数目大于等于其对应编号时,飞机才能被分配到廊桥。 理解起来…

10-27 CSP 赛前比赛记录

DNA 序列(DNA)哈希题啊,但是忘了怎么写哈希了 qwq,所以…… 思路大概就是维护一个长度为 \(k\) 的四进制数,类似于一个滑动窗口,就是除以 \(4\) 后加上右边新加的数乘上 \(4^k\),就可以得到其对应的哈希值,取模…

P3939 数颜色

这道题是暑假写的。但是当时数据结构学傻了,写了个莫队。 然后刚刚发现没过,连忙重新看题。 想了想发现跟可以跟Ynoi有一道区间众数题一个思路处理一下,直接二分就完了。 就记录一下每个数的出现次数。这里还有个小…

完整教程:Docker 搭建 Nginx 并启用 HTTPS 具体部署流程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AI开发微信小程序-有感

我先有一版html代码(有一个个人网站,里面都是一些在线使用的工具) 抽取出了其中一个小功能,让AI根据现有html代码直接转成小程序 直接拿过来在微信小程序开发IDE上,进行测试 稍微调整一下,就OK了。 AI真的是太有…

价值流智能时代:DevOps平台如何成为企业高效交付的核心引擎? - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …