mybatis plus开发过程中遇到的问题记录及解决

2023-08-06 0 2,795

目录

本文主要记录本人使用 mybatis plus 开发过程中碰到的问题,以及解决方案

## 以下 mybatis plus 统一简称 mp

一、使用 mp 生成代码

1、使用saveOrUpdateBatch或者saveBatch等新增修改方法

问题情况:

MybatisPlusException: error: can not execute. because can not find column for id from entity

原因:

不能执行。因为无法从实体中找到id列使用 mp 自动生成代码时,可能有这一行代码,会导致不生成主键 ID,变成自定义基础的Entity类,公共字段

strategy.setSuperEntityColumns(\"id\")

解决方法:

将上面这行代码注释即可

可能生成 ID 之后任旧无法执行,检查下面的原因

可能会存在实体类属性与数据库字段不一致的情况,所以我们在使用 mp 生成实体类时,最好在生成策略中加上这个行

strategy.setEntityTableFieldAnnotationEnable(true);

目的:生成之后的实体类中的每个属性会多出一个注解,来用于属性和数据库字段的对应

 @TableField(\"id\")

2、生成实体类时

数据库中的 int 类型 ID 变成了 String

问题情况:

mybatis plus开发过程中遇到的问题记录及解决

原因及解决方法:

我这里是 Mysql 数据库,生成代码时,做数据库类型转换时,原本选择的是 Oracle 数据库,改成 Mysql 数据的类型就可以

mybatis plus开发过程中遇到的问题记录及解决

3、引用第2钟错误当我们使用 mp 生成代码的时候只想生成实体类

问题情况:

引用第2钟错误,当我们使用 mp 生成代码的时候,可能实体类或者某一个文件中的代码生成的有问题,需要重新生成,但是又不想覆盖其他 Controller 、Mapper 等文件,我们如何选择只生成实体类?

解决方法:

我百度搜过,大佬们生成代码时,基本上都是生成所有的文件,所以我就自己开始研究。

请看下面这段代码,大家应该都明白这是什么意思,就是让我们生成的 mapper.xml 生成到我们指定的 resource 的文件夹下面,那么它原本的 xml 为什么不会生成了呢?

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + \"/src/main/resources/mapperWorkDiscovery/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        //让默认生成 mapper 的目录不再生成
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

关键点在这一行代码

templateConfig.setXml(null);

在配置模板的时候,我们设置了模板的 xml 为null,那么在我们改变 xml 的生成路径之后,原本的xml 就不会自己生成了,所以我想会不会有 .setMapper(null) 、 .setController(null) 的方法呢,于是我就自己尝试了一下,加上这几行代码

templateConfig.setMapper(null);
templateConfig.setController(null);
templateConfig.setService(null);
templateConfig.setServiceImpl(null);

这样重新生成之后,就只会生成 Entity 实体类了。

二、使用 mp 封装的方法时

1、使用修改方法,修改对象某一字段为null

问题情况:开发过程中,我们不可避免的会碰到这样的一个场景,需要修改对象某一个字段的值为 null,原本我们用 mybatis 时,修改方法会有两个

  • updateByPrimaryKey 对你注入的字段全部更新(不判断是否为Null);我们可以用这个来更新 null 值
  • updateByPrimaryKeySelective 会对字段进行判断再更新(如果为Null就忽略更新)

但是 mp 中的 update 方法是默认只更新不为 null 的值

例如:这样是更新不了对应字段为 null 的

        TSysUseraccount tSysUseraccount = sysUseraccountMapper.selectById(84);
        tSysUseraccount.setfExtensionnumber(null);
        sysUseraccountMapper.updateById(tSysUseraccount);
//执行的 sql 语句
UPDATE T_Sys_UserAccount SET F_UserCode=\'cs\', F_DeleteFlag=0 WHERE F_UserId=84

解决方法:

使用 LambdaUpdateWrapper 强制设置字段值为 null

        TSysUseraccount tSysUseraccount = sysUseraccountMapper.selectById(84);
        LambdaUpdateWrapper<TSysUseraccount> userUpdateWrapper = new UpdateWrapper<TSysUseraccount>().lambda()
                .eq(TSysUseraccount::getfUserid,tSysUseraccount.getfUserid())
                .set(TSysUseraccount::getfExtensionnumber,null);
        sysUseraccountMapper.update(tSysUseraccount,userUpdateWrapper);
// 执行的 sql 语句
UPDATE T_Sys_UserAccount SET F_UserCode=\'cs\', F_DeleteFlag=0, F_ExtensionNumber=null WHERE F_UserId = 84

三、自定义 sql 查询

1、mapper 接口中注解查询

 @Select({\"<script>\",
            \"SELECT IFNULL(sum( IFNULL(detail.amount,0) ),0) as total  FROM T_Lhgy_Work_Plan plan, T_Lhgy_Work_Plan_Detail detail WHERE plan.id = detail.plan_id AND plan.delete_flag = 0 AND detail.delete_flag = 0 AND plan.object_id = #{yhCompanyId}\",
            \"<when test=\'startTime!=null\'>\",
            \"AND date_format(plan.create_date,\'%Y-%m-%d\')  >= #{startTime}\",
            \"</when>\",
            \"<when test=\'endTime!=null\'>\",
            \"AND date_format(plan.create_date,\'%Y-%m-%d\') <= #{endTime}\",
            \"</when>\",
            \"</script>\"})
    List<Map<String, Object>> selectSumAmountByYhCompany(@Param(\"yhCompanyId\") Integer yhCompanyId,@Param(\"startTime\") String startTime,@Param(\"endTime\") String endTime);

问题情况:

mybatis 报The content of elements must consist of well-formed character data or markup. 语法格式错误

问题原因:

原来在xml中使用“<” “>” “&” 等一些这样的操作符时,xml会把它当成一个新的元素开始;

解决方法:

使用< ![CDATA[" 标记开始,以"]]> 包裹在< ![CDATA[" 标记开始,以"]]> 里包裹的元素,在xml解析时会被解析器忽略

比如 >= 可以写成 <![CDATA[ >= ]]>

<= 可以写成 <![CDATA[ <= ]]>

 @Select({\"<script>\",
            \"SELECT IFNULL(sum( IFNULL(detail.amount,0) ),0) as total  FROM T_Lhgy_Work_Plan plan, T_Lhgy_Work_Plan_Detail detail WHERE plan.id = detail.plan_id AND plan.delete_flag = 0 AND detail.delete_flag = 0 AND plan.object_id = #{yhCompanyId}\",
            \"<when test=\'startTime!=null\'>\",
            \"AND date_format(plan.create_date,\'%Y-%m-%d\') <![CDATA[ >= ]]> #{startTime}\",
            \"</when>\",
            \"<when test=\'endTime!=null\'>\",
            \"AND date_format(plan.create_date,\'%Y-%m-%d\') <![CDATA[ <= ]]> #{endTime}\",
            \"</when>\",
            \"</script>\"})
    List<Map<String, Object>> selectSumAmountByYhCompany(@Param(\"yhCompanyId\") Integer yhCompanyId,@Param(\"startTime\") String startTime,@Param(\"endTime\") String endTime);

四、使用 mybatis plus 性能分析插件

@Configuration
public class MybatisPlusConfig {
    /**
     * 打印 sql
     */
    @Bean
    @Profile({\"dev\",\"pro\"})// 设置 dev pro 环境开启日志打印
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        //格式化sql语句
        Properties properties = new Properties();
        properties.setProperty(\"format\", \"false\");
        performanceInterceptor.setProperties(properties);
        return performanceInterceptor;
    }
}

问题:3.2 无法使用此性能分析插件,导包时无法导入

原因:如果 mp 在3.1版本时使用是不会有问题的,但是如果你的 mp 是3.2的版本,就无法使用这个插件了,因为 mp 在3.2的版本已经移除了这个性能分析插件并推荐使用第三方插件。

3.1 mp 源码

mybatis plus开发过程中遇到的问题记录及解决

3.2 mp 源码,已经没有了 PerformanceInterceptor

mybatis plus开发过程中遇到的问题记录及解决

解决方案:

将 3.1 的源码复制出来,自定义一个 sql 性能分细插件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package me.zhengjie.config;
import cn.hutool.db.sql.SqlFormatter;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
/**
 *  由于 mybatis plus 3.2 升级之后移除了性能分析的插件,所以此处手动引入 3.1 的性能分析插件
 */
@Intercepts({@Signature(
    type = StatementHandler.class,
    method = \"query\",
    args = {Statement.class, ResultHandler.class}
), @Signature(
    type = StatementHandler.class,
    method = \"update\",
    args = {Statement.class}
), @Signature(
    type = StatementHandler.class,
    method = \"batch\",
    args = {Statement.class}
)})
public class PerformanceInterceptor implements Interceptor {
    private static final Log logger = LogFactory.getLog(PerformanceInterceptor.class);
    private static final String DruidPooledPreparedStatement = \"com.alibaba.druid.pool.DruidPooledPreparedStatement\";
    private static final String T4CPreparedStatement = \"oracle.jdbc.driver.T4CPreparedStatement\";
    private static final String OraclePreparedStatementWrapper = \"oracle.jdbc.driver.OraclePreparedStatementWrapper\";
    private long maxTime = 0L;
    private boolean format = false;
    private boolean writeInLog = false;
    private Method oracleGetOriginalSqlMethod;
    private Method druidGetSQLMethod;
    private static final SqlFormatter SQL_FORMATTER = new SqlFormatter();
    public PerformanceInterceptor() {
    }
    /** @deprecated */
    @Deprecated
    public static String sqlFormat(String boundSql, boolean format) {
        if (format) {
            try {
                return SQL_FORMATTER.format(boundSql);
            } catch (Exception var3) {
                ;
            }
        }
        return boundSql;
    }
    public Object intercept(Invocation invocation) throws Throwable {
        Object firstArg = invocation.getArgs()[0];
        Statement statement;
        if (Proxy.isProxyClass(firstArg.getClass())) {
            statement = (Statement)SystemMetaObject.forObject(firstArg).getValue(\"h.statement\");
        } else {
            statement = (Statement)firstArg;
        }
        MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);
        try {
            statement = (Statement)stmtMetaObj.getValue(\"stmt.statement\");
        } catch (Exception var20) {
            ;
        }
        if (stmtMetaObj.hasGetter(\"delegate\")) {
            try {
                statement = (Statement)stmtMetaObj.getValue(\"delegate\");
            } catch (Exception var19) {
                ;
            }
        }
        String originalSql = null;
        String stmtClassName = statement.getClass().getName();
        Class clazz;
        Object stmtSql;
        if (\"com.alibaba.druid.pool.DruidPooledPreparedStatement\".equals(stmtClassName)) {
            try {
                if (this.druidGetSQLMethod == null) {
                    clazz = Class.forName(\"com.alibaba.druid.pool.DruidPooledPreparedStatement\");
                    this.druidGetSQLMethod = clazz.getMethod(\"getSql\");
                }
                stmtSql = this.druidGetSQLMethod.invoke(statement);
                if (stmtSql instanceof String) {
                    originalSql = (String)stmtSql;
                }
            } catch (Exception var18) {
                var18.printStackTrace();
            }
        } else if (\"oracle.jdbc.driver.T4CPreparedStatement\".equals(stmtClassName) || \"oracle.jdbc.driver.OraclePreparedStatementWrapper\".equals(stmtClassName)) {
            try {
                if (this.oracleGetOriginalSqlMethod != null) {
                    stmtSql = this.oracleGetOriginalSqlMethod.invoke(statement);
                    if (stmtSql instanceof String) {
                        originalSql = (String)stmtSql;
                    }
                } else {
                    clazz = Class.forName(stmtClassName);
                    this.oracleGetOriginalSqlMethod = this.getMethodRegular(clazz, \"getOriginalSql\");
                    if (this.oracleGetOriginalSqlMethod != null) {
                        this.oracleGetOriginalSqlMethod.setAccessible(true);
                        if (null != this.oracleGetOriginalSqlMethod) {
                            Object stmtSql1 = this.oracleGetOriginalSqlMethod.invoke(statement);
                            if (stmtSql1 instanceof String) {
                                originalSql = (String)stmtSql1;
                            }
                        }
                    }
                }
            } catch (Exception var17) {
                ;
            }
        }
        if (originalSql == null) {
            originalSql = statement.toString();
        }
        originalSql = originalSql.replaceAll(\"[\\\\s]+\", \" \");
        int index = this.indexOfSqlStart(originalSql);
        if (index > 0) {
            originalSql = originalSql.substring(index);
        }
        long start = SystemClock.now();
        Object result = invocation.proceed();
        long timing = SystemClock.now() - start;
        Object target = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(target);
        MappedStatement ms = (MappedStatement)metaObject.getValue(\"delegate.mappedStatement\");
        StringBuilder formatSql = (new StringBuilder()).append(\" Time:\").append(timing).append(\" ms - ID:\").append(ms.getId()).append(\"\\n\").append(\"Execute SQL:\").append(sqlFormat(originalSql, this.format)).append(\"\\n\");
        if (this.isWriteInLog()) {
            if (this.getMaxTime() >= 1L && timing > this.getMaxTime()) {
                logger.error(formatSql.toString());
            } else {
                logger.debug(formatSql.toString());
            }
        } else {
            System.err.println(formatSql.toString());
            Assert.isFalse(this.getMaxTime() >= 1L && timing > this.getMaxTime(), \" The SQL execution time is too large, please optimize ! \", new Object[0]);
        }
        return result;
    }
    public Object plugin(Object target) {
        return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
    }
    public void setProperties(Properties prop) {
        String maxTime = prop.getProperty(\"maxTime\");
        String format = prop.getProperty(\"format\");
        if (StringUtils.isNotEmpty(maxTime)) {
            this.maxTime = Long.parseLong(maxTime);
        }
        if (StringUtils.isNotEmpty(format)) {
            this.format = Boolean.valueOf(format).booleanValue();
        }
    }
    public Method getMethodRegular(Class<?> clazz, String methodName) {
        if (Object.class.equals(clazz)) {
            return null;
        } else {
            Method[] var3 = clazz.getDeclaredMethods();
            int var4 = var3.length;
            for(int var5 = 0; var5 < var4; ++var5) {
                Method method = var3[var5];
                if (method.getName().equals(methodName)) {
                    return method;
                }
            }
            return this.getMethodRegular(clazz.getSuperclass(), methodName);
        }
    }
    private int indexOfSqlStart(String sql) {
        String upperCaseSql = sql.toUpperCase();
        Set<Integer> set = new HashSet();
        set.add(upperCaseSql.indexOf(\"SELECT \"));
        set.add(upperCaseSql.indexOf(\"UPDATE \"));
        set.add(upperCaseSql.indexOf(\"INSERT \"));
        set.add(upperCaseSql.indexOf(\"DELETE \"));
        set.remove(Integer.valueOf(-1));
        if (CollectionUtils.isEmpty(set)) {
            return -1;
        } else {
            List<Integer> list = new ArrayList(set);
            list.sort(Comparator.naturalOrder());
            return ((Integer)list.get(0)).intValue();
        }
    }
    public PerformanceInterceptor setMaxTime(long maxTime) {
        this.maxTime = maxTime;
        return this;
    }
    public long getMaxTime() {
        return this.maxTime;
    }
    public PerformanceInterceptor setFormat(boolean format) {
        this.format = format;
        return this;
    }
    public boolean isFormat() {
        return this.format;
    }
    public PerformanceInterceptor setWriteInLog(boolean writeInLog) {
        this.writeInLog = writeInLog;
        return this;
    }
    public boolean isWriteInLog() {
        return this.writeInLog;
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

资源下载此资源下载价格为1小猪币,终身VIP免费,请先
由于本站资源来源于互联网,以研究交流为目的,所有仅供大家参考、学习,不存在任何商业目的与商业用途,如资源存在BUG以及其他任何问题,请自行解决,本站不提供技术服务! 由于资源为虚拟可复制性,下载后不予退积分和退款,谢谢您的支持!如遇到失效或错误的下载链接请联系客服QQ:442469558

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 mybatis plus开发过程中遇到的问题记录及解决 http://www.20zxx.cn/806675/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务