实现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 而做 ...
随机推荐
- MyBatis(RowBounds)分页了解内容
RowBounds 不在使用SQL实现分页 1.接口 List<User> getUserByRowBounds(); 2.mapper.xml <select id="g ...
- 结合ReentrantLock来看AQS的原理
AQS的定义 队列同步器 AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架,它使用了一个 int 成员变量表示同步状态,通过内置的 F ...
- js的一些小问题集合
1.等于号的应用 function reverse(){ var checkbox = document.getElementsByName("hobby"); for (let ...
- 【技术实战】Vue技术实战【四】
需求实战一 效果展示 代码展示 <template> <ARow> <ACol> <a-statistic-countdown :value="de ...
- .net通用RSA加密工具类
目前最流行的加密算法莫过于RSA了,以下是我们.net/.net core C#生成环境用的RSA加密工具类,在此分享给大家. using System; using System.IO; using ...
- python:时间模块dateutil
安装 pip install python-dateutil dateutil模块主要有两个函数,parser和rrule. 其中parser是根据字符串解析成datetime,而rrule则是根据定 ...
- [gin]基于切片实现crud
前言 代码参考自<Building Distributed Application in Gin> 需求:设计一个食谱相关的API,数据存放到切片中. 设计模型和API 模型 type R ...
- 一些不错的VSCode设置和插件
设置 同步设置 我们做的各项设置,不希望再到其他机器的时候还得再重新配置一次.VSCode中我们可以登陆微软账号或者GitHub账号,登陆后我们可以开启同步设置.开启设置同步,根据提示登陆即可. 允许 ...
- 解锁Spring组件扫描的新视角
本文分享自华为云社区<Spring高手之路10--解锁Spring组件扫描的新视角>,作者: 砖业洋__. 首先,我们将探讨一些Spring框架中IOC(Inversion of Cont ...
- 【腾讯云 Cloud Studio 实战训练营】提升开发效率与协作:探索腾讯云 Cloud Studio 的强大功能与优势
一.前言 前几天发生了一个故事,发生了这样一个情景:一位新加入的同事刚刚入职不久,领取了一台崭新的电脑.随后,他投身于一个新项目,但却遇到了一个困扰:由于这台电脑没有管理员权限,他无法在上面安装所需的 ...