实现MyBatisPlus自定义sql注入器
目标:新增mysql下的 插入更新的语法
INSERT INTO %s %s VALUES %s ON DUPLICATE KEY UPDATE %s
新增方法类,新增的方法名称为insertOrUpdate和insertOrUpdateBatch方法,但其mapper层的方法名为insertOrUpdate方法
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import java.util.List;
import java.util.Objects;
import static java.util.stream.Collectors.joining;
public class InsertOrUpdate extends AbstractMethod {
public InsertOrUpdate() {
super(MyBatisPlusMethod.INSERT_OR_UPDATE.getMethod());
}
public InsertOrUpdate(String method) {
super(method);
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
MyBatisPlusMethod sqlMethod = MyBatisPlusMethod.INSERT_OR_UPDATE;
String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf(ENTITY_DOT),
LEFT_BRACKET, RIGHT_BRACKET, null, COMMA);
String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf(ENTITY_DOT),
LEFT_BRACKET, RIGHT_BRACKET, null, COMMA);
String setScript = SqlScriptUtils.convertTrim(this.getUpdateValuePart(tableInfo, ENTITY_DOT),
null, null, null, COMMA);
String keyProperty = null;
String keyColumn = null;
// 表包含主键处理逻辑,如果不包含主键当普通字段处理
if (StringUtils.isNotBlank(tableInfo.getKeyProperty())) {
if (tableInfo.getIdType() == IdType.AUTO) {
/* 自增主键 */
keyGenerator = Jdbc3KeyGenerator.INSTANCE;
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
} else if (null != tableInfo.getKeySequence()) {
keyGenerator = TableInfoHelper.genKeyGenerator(this.methodName, tableInfo, builderAssistant);
keyProperty = tableInfo.getKeyProperty();
keyColumn = tableInfo.getKeyColumn();
}
}
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript, setScript);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource, keyGenerator, keyProperty, keyColumn);
}
protected String getMethod(MyBatisPlusMethod sqlMethod) {
return StringUtils.isBlank(methodName) ? sqlMethod.getMethod() : this.methodName;
}
protected String getUpdateValuePart(TableInfo tableInfo, String prefix) {
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
return fieldList.stream().map(i -> i.getSqlSet(false, prefix))
.filter(Objects::nonNull).collect(joining(NEWLINE));
}
}
新增该方法的枚举类
public enum MyBatisPlusMethod {
/**
* 插入
*/
INSERT_OR_UPDATE("insertOrUpdate", "插入更新一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s ON DUPLICATE KEY UPDATE %s\n</script>");
private final String method;
private final String desc;
private final String sql;
MyBatisPlusMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return method;
}
public String getDesc() {
return desc;
}
public String getSql() {
return sql;
}
}
继承并实现MyBatisPlus的mapper、service层的方法
mapper
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.chinacreator.c2.dao.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
public interface MyBatisPlusMapper<T> extends BaseMapper<T> {
/**
* 插入更新一条记录
*
* @param entity 实体对象
* @return
*/
int insertOrUpdate(@Param(Constants.ENTITY) T entity);
}
service
package com.chinacreator.c2.chs.mp;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
public interface MyBatisPlusService<T> extends IService<T> {
/**
* 一句sql执行插入更新语句
*
* @param entityList 需要插入更新的实体
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
default boolean insertOrUpdateBatch(Collection<T> entityList) {
return insertOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize);
/**
* 一句sql执行插入更新语句
*
* @param entity 需要插入更新的实体
* @return 是否成功
*/
boolean insertOrUpdate(T entity);
}
serviceImpl
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.apache.ibatis.binding.MapperMethod;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
public class MyBatisPlusServiceImpl<M extends MyBatisPlusMapper<T>, T> extends ServiceImpl<M, T> implements MyBatisPlusService<T> {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
String mapperStatementId = mapperClass.getName() + StringPool.DOT + MyBatisPlusMethod.INSERT_OR_UPDATE.getMethod();
return SqlHelper.executeBatch(entityClass, log, entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<Object> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.insert(mapperStatementId, param);
});
}
@Override
public boolean insertOrUpdate(T entity) {
return SqlHelper.retBool(getBaseMapper().insertOrUpdate(entity));
}
}
新增自定义的MyBatisPlus自定义注入器
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.chinacreator.c2.dao.mapper.InsertBatchMethod;
import java.util.List;
public class MyBatisPlusSqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加方法,保留mybatis plus自带方法, 可以先获取super.getMethodList(),再添加add
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new InsertOrUpdate());
return methodList;
}
}
在MyBatisPlus的配置文件类上 创建该自定义注入器的bean对象
import com.chinacreator.c2.chs.mp.MyBatisPlusSqlInjector;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
public class MyBatisPlusConfig {
@Bean
public MyBatisPlusSqlInjector customizedSqlInjector() {
return new MyBatisPlusSqlInjector();
}
}
对使用官方生成的mapper、service、serviceImpl文件的继承类上改为我这边新增的
最后再调用service或mapper下的insertOrUpdate方法或insertOrUpdateBatch方法
实现MyBatisPlus自定义sql注入器的更多相关文章
- Mybatis-Plus如何自定义SQL注入器?
有关Mybatis-Plus常用功能之前有做过一篇总结: MyBatisPlus常用功能总结!(附项目示例) 一.什么是SQL注入器 我们在使用Mybatis-Plus时,dao层都会去继承BaseM ...
- mybatis-plus 自定义SQL,XML形式,传参的几种方式
mybatis-plus 自定义SQL,XML形式,传参的几种方式 前提说明 所涉及文件 传参类型说明 1.Java代码中使用QueryWrapper动态拼装SQL 2.简单类型参数(如String, ...
- SpringBoot集成MyBatis-Plus自定义SQL
1.说明 本文介绍Spring Boot集成MyBatis-Plus框架后, 基于已经创建好的Spring Boot工程, 添加自定义的SQL实现复杂查询等操作. 自定义SQL主要有两种方式, 一种是 ...
- 小书MybatisPlus第3篇-自定义SQL
本文档为一个系列,前面章节: 小书MybatisPlus第1篇-整合SpringBoot快速开始增删改查 小书MybatisPlus第2篇-条件构造器的应用及总结 书接上回,虽然Mybatis Plu ...
- spring boot集成mybatis-plus插件进行自定义sql方法开发时报nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
spring boot集成mybatis-plus插件进行自定义sql方法开发时报nested exception is org.apache.ibatis.binding.BindingExcept ...
- phpcmsv9自定义sql语句查询模型实现
在phpcmsv9中,自定义sql语句查询可不太好实现,传入sql语句查询很容易被内部转入生成一系列莫名其妙的sql语句,比如最佳前缀等等,直接造成sql语句查询错误,在此也提供两种解决办法,1修改底 ...
- thinkjs中自定义sql语句
一直以为在使用thinkjs时,只能是它自带的sql语句查询,当遇到类似于这样的sql语句时,却不知道这该怎样来写程序,殊不知原来thinkjs可以执行自定义sql语句 SELECT * from a ...
- 11月16日《奥威Power-BI基于SQL的存储过程及自定义SQL脚本制作报表》腾讯课堂开课啦
上周的课程<奥威Power-BI vs微软Power BI>带同学们全面认识了两个Power-BI的使用情况,同学们已经迫不及待想知道这周的学习内容了吧!这周的课程关键词—— ...
- django不定义model,直接执行自定义SQL
如果不想定义model,直接执行自定义SQL,可如下操作: 1. 通过 connections获取db连接,如果是多个数据库,connections['dbName'] 来选择 2. 获取游标 cur ...
- Python Django 之 直接执行自定义SQL语句(二)
转载自:https://my.oschina.net/liuyuantao/blog/712189 一般来说,最好用 Django 自带的模型来实现这些操作.这里仅仅只是为了学习使用原始 SQL 而做 ...
随机推荐
- Linux内核笔记(三)内核编程语言和环境
学习概要: Linux内核使用的编程语言.目标文件格式.编译环境.内联汇编.语句表达式.寄存器变量.内联函数 c和汇编函数之间的相互调用机制Makefile文件的使用方法. as86汇编语言语法 汇编 ...
- vulnhub_me and my grilfriend
解题步骤 主机nmap扫描,开放22和80端口 访问该ip,发现只能本地访问 查看源代码,提示需要使用x-forwarded-for的请求头,可以在burp suite中每次添加一个请求头,也可以使用 ...
- centos7升级内核到最新稳定版
前言 centos7默认的内核版本才3.10,诸如VXLAN.eBPF等特性无法体验,因此需要升级.目前(2022.02)Linux的内核版本已更新到5.16. 步骤 更新仓库 yum update ...
- 一文理解GIT的代码冲突
对于GIT,不知道有没有人和我一样,很长时间都是小心翼翼.紧张兮兮,生怕一不小心,自己辛苦写的代码没了. 特别是代码冲突,更是难到我无法理解,每次都要求助于百度,跟着人家的教程一步步解决,下一次还是这 ...
- Web通用漏洞--CSRF
Web通用漏洞--CSRF 漏洞简介 CSRF(Cross Site Request Forgery, 跨站请求伪造/客户端请求伪造),即通过伪造访问数据包并制作成网页的形式,使受害者访问伪造网页,同 ...
- LabVIEW图形化TensoRT工具包的安装下载分享
前言 Hello,大家好,我是virobotics(仪酷智能)今天我们一起来看一下如何安装[LabVIEWTensoRT工具包]. 一.LabVIEW图形化TensoRT工具包简介 工具包特点: 图形 ...
- 《高级程序员 面试攻略 》RabbitMQ 如何实现可靠性
RabbitMQ 提供了多种机制来实现消息传递的可靠性.下面是一些常见的方法: 1. 持久化消息:RabbitMQ 允许将消息标记为持久化,以确保即使在发生故障或重启后,消息也不会丢失.通过将消息的` ...
- 【pandas小技巧】--DataFrame的显示参数
我们在jupyter notebook中使用pandas显示DataFrame的数据时,由于屏幕大小,或者数据量大小的原因,常常会觉得显示出来的表格不是特别符合预期. 这时,就需要调整pandas显示 ...
- pytest-xdist分布式测试原理浅析
pytest-xdist执行流程: 解析命令行参数:pytest-xdist 会解析命令行参数,获取用户指定的分发模式.进程数.主机列表等信息. 加载测试用例:pytest-xdist 会加载所有的 ...
- C盘无法创建文件处理
icacls c:\ /setintegritylevel M 打开终端执行上方命令,亲测可用