首页 > 数据库 >实现MyBatisPlus自定义sql注入器

实现MyBatisPlus自定义sql注入器

时间:2023-11-10 14:14:22浏览次数:60  
标签:tableInfo mybatisplus MyBatisPlus String 自定义 sql import com public

目标:新增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方法

标签:tableInfo,mybatisplus,MyBatisPlus,String,自定义,sql,import,com,public
From: https://www.cnblogs.com/dkpp/p/17823960.html

相关文章

  • MySQL导入导出数据表容量的一个问题场景
    朋友提了一个MySQL数据导出导入的问题。问题描述:从源库(兼容MySQL协议的TDSQL,selectversion()=5.7,test表字符集是utf8,test是个分区表)通过如下指令,导出一份数据,SQL格式的,文件6G,mysqldump-hx.x.x.x-P3306-uroot-proot--databasesdbtest--tablestest--complete-insert--s......
  • POSTGRESQL 如何用系统函数来诊断权限问题
    开发人员很少关注于数据库系统的权限,而POSTGRESQL相对于MYSQL来说,他的权限是复杂的,尤其在一些规范的企业,对于权限的要求很高,而随时掌握账号对于数据库OBJECTS的权限的状态,在很多项目中是乙方需要知道该怎么做的。我们从上到下,一一给大家进行演示,你的用户组需要针对PG中不同的数据......
  • mysql 查询报错Expression #1 of SELECT list is not in GROUP BY clause and contain
    这个错误是由于MySQL的新版本中默认开启了ONLY_FULL_GROUP_BY模式,即在GROUPBY语句中的SELECT列表中,只能包含分组或聚合函数,不能包含其他列。而你的查询语句中出现了一个列senior_two.score.student_id,它既没有被分组也没有被聚合,因此MySQL报出了这个错误。5.7版本以下不......
  • Oracle常用SQL-处理异常锁表
    锁表查询的代码有以下的形式:selectcount(*)fromv$locked_object;select*fromv$locked_object;查看哪个表被锁selectb.owner,b.object_name,a.session_id,a.locked_mode,a.object_idfromv$locked_objecta,dba_objectsbwhereb.object_id=a.object_id;查看是哪个ses......
  • 【Qt初入江湖】Qt QSqlTableModel 底层架构、原理详细描述
    鱼弦:内容合伙人、新星导师、全栈领域创作新星创作者、51CTO(Top红人+专家博主)、github开源爱好者(go-zero源码二次开发、游戏后端架构https://github.com/Peakchen) QtQSqlTableModel是Qt中用于实现基于数据库表格的模型类,它继承自QAbstractTableModel。QSqlTableModel封装了对......
  • SQL Server 备份加密的先决条件
    --1创建密钥createmasterkeyencryptionbypassword='密钥'--创建证书createCERTIFICATEBackupCertificate_mywithsubject=N'sparksoftcertificate'--3备份证书和密钥文件BACKUPCERTIFICATEBackupCertificate_myTOFILE='E:\BackupCertificate_my.ce......
  • SQL
    SQLSelectSELECTcolumn1,column2,...FROMtable_name;SelectDistinctselectuniqueuintSELECTDISTINCTcolumn1,column2,...FROMtable_name;SELECTDISTINCTCountryFROMCustomers;WhereSELECTcolumn1,column2,...FROMtable_nameWHEREconditio......
  • docker mysql
    dockerrun-d--namemysql--restart=always--privileged=true\-v/opt/mysql/log:/var/log/mysql\-v/opt/mysql/data:/var/lib/mysql\-v/opt/mysql/conf.d:/etc/mysql/conf.d\-v/etc/localtime:/etc/localtime:ro\-eMYSQL_ROOT_PASSWORD=123456-p33......
  • MySQL 死锁后事务无法回滚是真的吗?
    MySQL作为目前互联网企业使用最多的,或者说在基于成本下,最流行的数据库之一,MySQL在国内使用者众多,那么在MySQL偶然安装后,在使用中出现死锁后,死锁中的事务到底能不能回滚 ?我们来进行相关的实验我们先验证一遍1 我们打开一个MySQL版本为8.027 官方版本2通过下面的操作我们可以......
  • MySQL 内部Server 层机制
    主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。1.连接器像navicat、JDBC、MySQL等客户端软件需要先和mysql建立通信之后......