--- title: 常见问题 sidebar: order: 6 --- 本文档收录了 MyBatis-Plus 使用时遇到的各种常见问题,如果您在使用 MyBatis-Plus 的时候遇到了问题,请您优先查看本文档。 ## 如何排除非表中字段? 以下三种方式选择一种即可: - 使用 `transient` 修饰 ```java private transient String noColumn; ``` - 使用 `static` 修饰 ```java private static String noColumn; ``` - 使用 `TableField` 注解 ```java @TableField(exist=false) private String noColumn; ``` ## 如何排除实体父类属性? 使用 `transient` 修饰需要排除的父类属性 ```java /** * 忽略父类 createTime 字段映射 */ private transient String createTime; ``` ## 出现 `Invalid bound statement (not found)` 异常 出现该异常通常是由于配置不正确或者 Mapper 没有被正确扫描到导致的。解决方案如下: - 检查是否存在 jar 包冲突。 - 检查 Mapper.java 的扫描路径: - 方法一:在 `Configuration` 类上使用注解 `MapperScan` ```java @Configuration @MapperScan("com.yourpackage.*.mapper") public class YourConfigClass{ ... } ``` - 方法二:在 `Configuration` 类中配置 `MapperScannerConfigurer`([查看示例](https://gitee.com/baomidou/mybatisplus-spring-boot/blob/config%E6%96%B9%E5%BC%8F/src/main/java/com/baomidou/springboot/config/MybatisPlusConfig.java)) ```java @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer(); // 可以通过环境变量获取你的 mapper 路径,这样 mapper 扫描可以通过配置文件配置了 scannerConfigurer.setBasePackage("com.yourpackage.*.mapper"); return scannerConfigurer; } ``` - 检查是否指定了主键。如果未指定,将导致 `selectById` 相关 ID 无法操作。请使用注解 `@TableId` 注解表 ID 主键。当然,`@TableId` 注解可以省略,但是你的主键必须叫 id(忽略大小写)。 - 不要使用原生的 SqlSessionFactory,请使用 MybatisSqlSessionFactory。 - 检查是否自定义了 SqlInjector,是否复写了 `getMethodList()` 方法。在该方法中是否注入了你需要的方法(可参考 DefaultSqlInjector)。 - IDEA 默认的 build 步骤可能会导致 mapper 文件无法正常编译到对应的 resources 文件夹中。请检查 build 后相关资源文件夹是否有对应的 XML 文件。如果没有,请调整 IDEA 的 build 设置。推荐调整为 Maven 或 Gradle 的 build。 ## 自定义 SQL 无法执行 问题描述:指在 XML 中里面自定义 SQL,却无法调用。本功能同 `MyBatis` 一样需要配置 XML 扫描路径: - Spring MVC 配置(参考[mybatisplus-spring-mvc](https://gitee.com/baomidou/mybatisplus-spring-mvc/blob/dev/src/main/resources/spring/spring-mybatis.xml)) ```xml ... ``` - Spring Boot 配置(参考[mybatisplus-spring-boot](https://gitee.com/baomidou/mybatisplus-spring-boot/blob/2.x/src/main/resources/application.yml)) ```yaml mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml ``` - 对于`IDEA`系列编辑器,XML 文件是不能放在 java 文件夹中的,IDEA 默认不会编译源码文件夹中的 XML 文件,可以参照以下方式解决: - 将配置文件放在 resource 文件夹中 - 对于 Maven 项目,可指定 POM 文件的 resource ```xml src/main/java **/*.xml src/main/resources ``` :::note 注意!Maven 多模块项目的扫描路径需以 `classpath*:` 开头 (即加载多个 jar 包下的 XML 文件) ::: ## 启动异常时异常问题排查 - 异常一: ```txt java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class ``` MapperScan 需要排除 com.baomidou.mybatisplus.mapper.BaseMapper 类 及其 子类(自定义公共 Mapper),比如: ```java import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface SuperMapper extends BaseMapper { // your methods } ``` - 异常二: ```txt Injection of autowired ``` 原因:低版本不支持泛型注入,请升级 Spring 版本到 4+ 以上。 - 异常三: ```txt java.lang.NoSuchMethodError: org.apache.ibatis.session.Configuration.getDefaultScriptingLanguageInstance() Lorg/apache/ibatis/scripting/LanguageDriver ``` 版本引入问题:3.4.1 版本里没有,3.4.2 里面才有! ## 关于 Long 型主键填充不生效的问题 检查是不是用了`long`而不是`Long`! :::tip `long`类型默认值为 0,而 MP 只会判断是否为 `null` ::: ## 生成主键太长导致 JS 精度丢失 JavaScript 无法处理 Java 的长整型 Long 导致精度丢失,具体表现为主键最后两位永远为 0,解决思路: Long 转为 String 返回 - FastJson 处理方式 ```java {6} @Override public void configureMessageConverters(List> converters) { FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fjc = new FastJsonConfig(); // 配置序列化策略 fjc.setSerializerFeatures(SerializerFeature.BrowserCompatible); fastJsonConverter.setFastJsonConfig(fjc); converters.add(fastJsonConverter); } ``` - JackJson 处理方式 - 方式一 ```java // 注解处理,这里可以配置公共 baseEntity 处理 @JsonSerialize(using=ToStringSerializer.class) public long getId() { return id; } ``` - 方式二 ```java // 全局配置序列化返回 JSON 处理 final ObjectMapper objectMapper = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); ``` - 比较一般的处理方式:增加一个 `public String getIdStr()` 方法,前台获取 `idStr` ## 插入或更新的字段有 空字符串 或者 `null` 插入、更新时是否带上某个字段,以及 Wrapper 根据实体生成 where 条件时是否带上某个字段,由 [FieldStrategy](/reference/annotation/#insertstrategy) 决定: - ALWAYS:总是加入 SQL,不做判断 - NOT_NULL:非 NULL 才加入 SQL,全局默认策略 - NOT_EMPTY:非空才加入 SQL(只对字符串类型生效,其他类型等同于 NOT_NULL) - DEFAULT:跟随全局配置,只用于注解 - NEVER:不加入 SQL :::note `FieldStrategy.IGNORED` 已在 `3.5.11` 版本移除,请改用效果相同的 `FieldStrategy.ALWAYS`。 ::: 当用户有更新字段为 空字符串 或者 `null` 的需求时,需要对 `FieldStrategy` 策略进行调整: - 方式一:调整全局的验证策略 通过 [insertStrategy](/reference/#insertstrategy)、[updateStrategy](/reference/#updatestrategy)、[whereStrategy](/reference/#wherestrategy) 配置: ```yaml mybatis-plus: global-config: db-config: update-strategy: ALWAYS ``` - 方式二:调整字段验证注解 根据具体情况,在需要更新的字段上调整对应的策略,如更新时总是带上该字段(可以把字段更新为 `null`): ```java @TableField(updateStrategy = FieldStrategy.ALWAYS) ``` - 方式三:使用 `UpdateWrapper` (3.x) 使用以下方法来进行更新或插入操作: ```java //updateAllColumnById(entity) // 全部字段更新: 3.0已经移除 mapper.update( new User().setName("mp").setAge(3), Wrappers.lambdaUpdate() .set(User::getEmail, null) //把email设置成null .eq(User::getId, 2) ); //也可以参考下面这种写法 mapper.update( null, Wrappers.lambdaUpdate() .set(User::getAge, 3) .set(User::getName, "mp") .set(User::getEmail, null) //把email设置成null .eq(User::getId, 2) ); ``` ## 字段类型为 `bit`、`tinyint(1)` 时映射为 `boolean` 类型 默认mysql驱动会把tinyint(1)字段映射为boolean: 0=false, 非0=true MyBatis 是不会自动处理该映射,如果不想把tinyint(1)映射为boolean类型: * 修改类型tinyint(1)为tinyint(2)或者int * 需要修改请求连接添加参数 `tinyInt1isBit=false`,如下: ```xml jdbc:mysql://127.0.0.1:3306/mp?tinyInt1isBit=false ``` ## 出现 2 个 `limit` 语句 原因:配了 2 个分页拦截器! 检查配置文件或者代码,只留一个! ## insert 后如何返回主键 insert 后主键会自动 set 到实体的 ID 字段,所以你只需要 getId() 就好 ## MP 如何查指定的几个字段 EntityWrapper.sqlSelect 配置你想要查询的字段 ```java //2.x EntityWrapper ew = new EntityWrapper<>(); ew.setSqlSelect("test_id as id, name, age");//只查询3个字段 List list = userService.selectList(ew); for(H2User u:list){ Assert.assertNotNull(u.getId()); Assert.assertNotNull(u.getName()); Assert.assertNull(u.getPrice()); // 这个字段没有查询出来 } //3.x mapper.selectList( Wrappers.lambdaQuery() .select(User::getId, User::getName) ); //或者使用QueryWrapper mapper.selectList( new QueryWrapper() .select("id","name") ); ``` ## Mapper 层二级缓存问题 我们建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现。 ## Mapper 层二级缓存刷新问题 如果你按照 mybatis 的方式配置第三方二级缓存,并且使用 2.0.9 以上的版本,则会发现自带的方法无法更新缓存内容,那么请按如下方式解决(二选一): 1.在代码中 mybatis 的 mapper 层添加缓存注释,声明 implementation 或 eviction 的值为 cache 接口的实现类 ```java @CacheNamespace(implementation=MybatisRedisCache.class,eviction=MybatisRedisCache.class) public interface DataResourceMapper extends BaseMapper{} ``` 2.在对应的 mapper.xml 中将原有注释修改为链接式声明,以保证 xml 文件里的缓存能够正常 ```xml ``` ## `Cause: org.apache.ibatis.type.TypeException:Error setting null for parameter #1 with JdbcType OTHER` 在 MyBatis-Plus 中, `jdbcTypeForNull` 是一个重要的配置选项, 它决定了如何将Java的 `null` 值映射到数据库中. 默认情况下, 当某个字段在 Java 中为 `null` 时, MyBatis-Plus 会将其映射为数据库中的 `JdbcType.OTHER` 值。但某些 JDBC 驱动程序(例如 Oracle) 不支持 `JdbcType.OTHER` ,因此默认设置会导致错误: `Cause: org.apache.ibatis.type.TypeException:Error setting null for parameter #1 with JdbcType OTHER . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLException: 无效的列类型: 1111`. 要设置 `jdbcTypeForNull` , 你需要在 MyBatis-Plus 的配置类中添加以下代码(任选其一即可): > Spring Bean 配置 ```java MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); configuration.setJdbcTypeForNull(JdbcType.NULL); sqlSessionFactory.setConfiguration(configuration); ``` > Yaml 配置 ```yaml mybatis-plus: configuration: jdbc-type-for-null: 'null' ``` > Properties 配置 ```properties mybatis-plus.configuration.jdbc-type-for-null=NULL ``` > XML 配置 ```xml ``` > 需要注意的是, 如果你在项目中自定义 `SqlSessionFactory` 可能导致 `jdbc-type-for-null` 配置失效. ## 无法通过 Page 对象在自定义 SQL 中传递参数 在自定义 SQL 中,由于 Page 对象继承自 RowBounds,在 Mapper 中无法直接获取。为了解决这个问题,请考虑以下替代方案: - 使用自定义的 Map 对象或者普通的 Java 对象来传递参数。 - 通过在方法参数中使用 @Param("page") int page, @Param("size") int size 来传递页码和每页大小。 这些方法可以帮助您在自定义 SQL 中正确传递参数,确保代码的顺利运行。 ## 如何使用 Map 下划线自动转驼峰 当使用 `resultType="java.util.Map"` 时,您可以通过以下步骤在 Spring Boot 中实现下划线自动转换为驼峰: 在您的 Spring Boot 项目中创建一个配置类。 ```java @Configuration public class MybatisConfigurationCustomizer { @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setObjectWrapperFactory(new MybatisMapWrapperFactory()); } } ``` 通过这样配置,您就可以实现自动将 Map 中的下划线转换为驼峰形式。这样,在 MyBatis 查询结果映射到 Map 对象时,键名会自动进行转换,使得您在代码中更加便捷地访问数据。 ## 如何在 Wrapper 中使用 `limit` 限制 SQL 您可以通过以下方式在 Wrapper 中使用 `limit` 限制 SQL 结果集: ```java // 仅获取一条数据 wrapper.last("limit 1"); ``` 这段代码会在 SQL 语句末尾添加 limit 1,以限制结果集返回的行数为 1。 ## 为什么将通用的批量插入操作放在 Service 层处理 将通用的批量插入操作放在 Service 层处理有以下原因: - SQL 长度存在限制:处理海量数据时,单条 SQL 可能无法执行或者容易引起内存泄漏、JDBC 连接超时等问题。 - 不同数据库的单条 SQL 批量语法不一致,不利于通用性。 - 解决方案:采用循环预处理批量提交的方法。虽然性能比单条 SQL 插入稍慢,但可以解决上述问题。 如果您想使用单条 SQL 插入方案,可以自行注入选装方法 [insertbatchsomecolumn](https://baomidou.com/pages/49cc81/#insertbatchsomecolumn),或查看[SQL 注入器](https://baomidou.com/pages/42ea4a/)中提供的方法。 ## 3.x版本中数据库关键字处理方法 在 MyBatis Plus 3.x 中,不再提供自动识别关键字进行处理的功能。处理数据库关键字的方法有以下几种: 1. 不同数据库对关键字的处理方式不同,因此很难维护。在数据库设计时,建议避免使用关键字作为字段名或表名。 2. 如果必须使用关键字,可以通过在字段或表名前后添加反引号(`)来进行处理,如下所示: ```java @TableField(value = "`status`") private Boolean status; ``` 综上所述,为了避免出现问题,建议尽量避免在数据库设计中使用关键字。 ## MybatisPlusException: Your property named "xxx" cannot find the corresponding database column name! 针对 MyBatis Plus 3.1.1 及更高版本出现的问题: 现象:在单元测试中没有问题,但是在启动服务器进行调试时出现该异常。 原因:在 3.1.1 版本及以后的版本中,针对字段缓存进行了优化,使用 `.class` 作为键来替换了原来的类名(className)。然而,当使用 dev-tools 时,可能会导致 `.class` 使用不同的类加载器加载,从而导致出现找不到属性的情况。 解决方案:移除 dev-tools 插件。这样可以避免使用不同的类加载器加载 `.class`,从而解决该异常问题。 ## Error attempting to get column "create_time" from result set. Cause: java.sql.SQLFeatureNotSupportedException 针对 MyBatis Plus 3.1.1 及更高版本出现的问题: 现象:在集成 Druid 数据源时,升级到 3.1.1 版本及之后的版本后,出现错误:java.sql.SQLFeatureNotSupportedException。而在 3.1.0 版本之前没有此问题。 原因:MyBatis Plus 3.1.1 版本及更高版本采用了新版 JDBC,对于新的日期类型(如 LocalDateTime)处理方式进行了升级。然而,Druid 在 1.1.21 版本之前不支持此特性,导致出现此异常。详细信息请参考[相关问题](https://github.com/baomidou/mybatis-plus/issues/1245)。 解决方案: 1. 将 Druid 数据源升级至 1.1.21 版本以上,以解决此问题。 2. 如果无法升级 Druid 数据源,可以选择保持 MyBatis Plus 版本在 3.1.0 及之前的版本。 3. 若要继续使用最新的 MyBatis Plus 版本,可以考虑更换其他兼容新版 JDBC 的数据源,以避免出现此异常。 ## 升级 MyBatis Plus 到 3.1.1 及更高版本后,新日期类型无法映射报错 如果您将 MyBatis Plus 从 3.1.0 及以下版本升级到较高版本,且遇到新日期类型(如 LocalDateTime)无法映射的报错,可能是由于以下原因: MP_3.1.0 及之前版本依赖的是 MyBatis 3.5.0。而 MP_3.1.1 升级了 MyBatis 的依赖到 3.5.1,而在 MyBatis 3.5.1 中,新日期类型需要 JDBC 驱动支持 JDBC 4.2 API。 如果您的 JDBC 驱动版本不支持 JDBC 4.2 API,就会出现无法映射新日期类型的报错。 参考 [MyBatis 官方博客](blog.mybatis.org) 的内容: ```text There is one backward incompatible changes since 3.5.0. Because of the fix for #1478 , LocalDateTypeHandler, LocalTimeTypeHandler and LocalDateTimeTypeHandler now require a JDBC driver that supports JDBC 4.2 API. [EDIT] These type handlers no longer work with Druid. Please see #1516 . ``` 解决方案: - 升级您的 JDBC 驱动至支持 JDBC 4.2 API 的版本。 - 如果无法升级 JDBC 驱动,可以考虑将 MyBatis Plus 版本回滚至 3.1.0 或之前的版本。 ## Failed to bind properties under "mybatis-plus.configuration.incomplete-result-maps[0].assistant.configuration.mapped-statements[0].parameter-map.parameter-mappings[0]" to org.apache.ibatis.mapping.ParameterMapping 如果您在将 Spring Boot 版本从 2.2.0 升级到更高版本时遇到此问题,可能是由于以下原因: 现象:在本地启动时没有问题,但是将打成 war 包部署到服务器时出现此问题。 原因:在 Spring Boot 2.2.0 中存在构造器注入的问题,导致 MyBatis 的私有构造器无法正确绑定属性,进而导致依赖 MyBatis 的框架(如 MyBatis Plus)报错。详细信息请参考 [相关 issue](https://github.com/spring-projects/spring-boot/issues/18670)。此问题已在 Spring Boot 2.2.1 中得到修复。 解决方案: 1. 将 Spring Boot 降级至 2.1.x 版本,或升级至 2.2.1 版本以上。建议直接升级至 Spring Boot 2.2.2 版本以获取更好的稳定性和修复。 ## 分离打包部署出现 ClassNotFoundException 现象:在开发工具中运行没有问题,但是将项目打包部署到服务器后,执行 Lambda 表达式时出现 ClassNotFoundException。 针对 MyBatis Plus 3.3.2 以下版本,如果在分离打包部署时出现 ClassNotFoundException 的问题,可能是因为在执行反序列化操作时,类加载器发生了错误。 解决方案: 1. 去除 `spring-boot-maven-plugin` 插件进行打包,或者 2. 升级至 MyBatis Plus 3.3.2 版本。您可以参考示例 [分离打包](https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-assembly) 进行操作。 ## 启用 MyBatis 内部日志记录 您可以通过以下两种方式来启用 MyBatis 内部的日志记录: **方式一:** 在您的 `application.yml` 或 `application.properties` 文件中添加以下配置: ```yaml mybatis-plus: configuration: # 如果项目无日志框架,可以考虑指定为 org.apache.ibatis.logging.stdout.StdOutImpl (请勿在实际生产中使用). log-impl: org.apache.ibatis.logging.stdout.StdOutImpl ``` 这将使用 MyBatis 内置的 StdOutImpl 日志记录实现将日志输出到控制台。 **方式二:** 在您的 `application.yml` 或 `application.properties` 文件中增加日志级别配置,以指定特定包的日志级别。例如: ```yaml logging: level: com.baomidou.example.mapper: debug ``` 这将指定 com.baomidou.example.mapper 包下的日志级别为 debug。您可以根据需要调整级别。 通过以上配置,您可以启用 MyBatis 内部的日志记录,并根据需要调整日志级别。 ## 如何在 update 时对字段进行自增操作 如果您想要在更新操作时对某个字段进行自增操作,您可以使用 MyBatis Plus 提供的 `Wrapper` 进行更新。以下是一种可行的解决方案: ```java UpdateWrapper wrapper = new UpdateWrapper<>(); wrapper.setSql("column = column + 1"); // 或者使用 Lambda 表达式 UpdateWrapper wrapper = new UpdateWrapper<>(); wrapper.setSql("column = column + 1"); // 调用 update 方法 baseMapper.update(null, wrapper); ``` 这样可以在更新时对字段进行自增操作。请注意,需要在 `setSql` 方法中直接指定 SQL 更新语句。 ## 如何全局处理数据库关键词 如果您想要全局处理数据库关键词,可以使用 MyBatis Plus 提供的全局配置。以下是配置示例(以 MySQL 为例): ```yaml mybatis-plus: global-config: db-config: column-format: "`%s`" ``` 这样配置后,MyBatis Plus 将会在生成 SQL 语句时,对数据库字段名称使用反引号(``)进行包裹,以确保不与数据库关键词冲突。 需要注意的是: - 如果您使用了 `@TableField` 注解,并希望保持全局格式化,需要设置参数 `keepGlobalFormat=true`。 - 您也可以在 `@TableField` 注解中直接指定固定格式的数据库关键词,例如 `@TableField("'status'")`。 通过以上配置,您可以全局处理数据库关键词,确保生成的 SQL 语句不会受到关键词影响。 ## 如何在 XML 中根据数据库类型选择不同的 SQL 片段 如果您想要在 XML 中根据数据库类型选择不同的 SQL 片段,您可以使用 MyBatis Plus 提供的 `database-id` 参数。以下是配置示例(以 MySQL 为例): ```yaml mybatis-plus: configuration: database-id: mysql ``` 这样配置后,MyBatis Plus 将会在执行 SQL 语句时,根据 `database-id` 参数选择不同的 SQL 片段。 您可以根据不同的写法在 XML 中进行判断: 1. 使用变量 `_databaseId`: ```xml ``` 2. 使用标签属性 `databaseId`: ```xml ``` 通过以上配置,您可以根据不同的数据库类型选择不同的 SQL 片段。 ## 为何 MyBatis Plus 不支持复合主键,强制唯一 ID 问题解答 MyBatis Plus 不支持复合主键并强制使用唯一的 ID,这是出于以下考虑: 1. 增加了表与表之间的相互依赖性:使用复合主键会使表与表之间的关系更加复杂,增加了维护和管理的难度。 2. 增加了数据复杂的约束、规则:复合主键会增加数据的约束和规则,例如需要约束唯一性,而完全可以使用联合索引来实现。 3. 增加了更新数据的限制:在更新数据时,需要更新所有复合主键的值,这增加了更新操作的限制和复杂性。 4. 严重的数据冗余和更新异常问题:复合主键可能导致数据冗余和更新异常的问题,特别是在大型系统中,可能会出现更新异常的情况。 5. 性能问题:使用复合主键时,查询某个 ID 时无法使用索引,会导致性能下降。 综上所述,虽然使用复合主键可以省去一个 ID 字段,但是这种做法的缺点大于优点,不建议也不推荐这样做。MyBatis Plus 坚持使用唯一的 ID,以保证数据管理的简单性、可维护性和性能。 ## 项目启动速度缓慢 - 初始化默认雪花ID导致 1. 查看本机hostname 2. 编辑系统hosts文件,将本机hostname写入至hosts文件 ```properties # 示例,例如我的hostname名字为nieqiurong-PC,那我在hosts文件配置如下即可 127.0.0.1 localhost nieqiurong-PC ``` - 检查数据库连接池初始化 碰到过使用hikari在linux系统下启动缓慢 解决方案: 在java启动命令中指定 -Djava.security.egd=file:/dev/urandom把获取随机数的方式从 /dev/random改为/dev/urandom 示例: java -Djava.security.egd=file:/dev/urandom -jar xxxx.jar ## 3.5.7+ 版本 Db.saveBatch 返回值一直为 false - 原因:驱动配置不兼容 > 解决方案:驱动连接去掉 `rewriteBatchedStatements=true` 配置 ## Page或List返回的结果集为null或者包含部分null元素 - 原因:mybatis默认情况下, 当返回行的所有列都是空时(含属性无法自动映射), 默认返回 null > 解决方案:配置returnInstanceForEmptyRow 为true ```yaml mybatis-plus: configuration: return-instance-for-empty-row: true ``` ## 当返回值为 Map 或 List<Map> 时,null 值对应的 key 没有添加至 Map 里 - 原因:mybatis默认情况下, 当返回 null 时,不会调用put方法 > 解决方案:配置callSettersOnNulls 为true ```yaml mybatis-plus: configuration: call-setters-on-nulls: true ``` ## 如何重写BaseMapper方法 重写接口方法请区分default方法和抽象接口方法,重写的方法需要以最终调用的实际方法为准. 抽象接口方法: 直接在XML重写此方法可完成 default方法: 直接重写真实调用的方法或者把原default重写为真实接口方法,然后在XML或注解的方式重写执行语句. ```java // 方式一: 注解式重写BaseMapper中selectPage方法(低版本下可能为接口方法,这里以新版default为例) @Override @Select("select * from h2user")

> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper); // 方式二: XML式重写BaseMapper中selectPage方法(低版本下可能为接口方法,这里以新版default为例) @Override

> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper); // 这里自己去XML里面重写selectPage的查询语句 // 方式三: 重写BaseMapper中selectPage方法 @Override default

> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper) { return xxxx(); //实际调用的自己定义的真实接口方法 } ``` ## Kotlin调用接口defalut方法出现 Invalid bound statement (not found) - 原因:https://blog.jetbrains.com/kotlin/2020/07/kotlin-1-4-m3-generating-default-methods-in-interfaces/ > 解决方案:配置编译插件的编译参数 -Xjvm-default=all ```xml org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} -Xjsr305=strict -Xjvm-default=all ``` ```groovy compileKotlin { kotlinOptions { freeCompilerArgs = ['-Xjvm-default=all'] } } ``` ## Encountered unexpected token: "\n\n\n" 或 Could not set parameters for mapping - 原因:jsqlParser4.9,连续的换行会认为是结束语句会抛出Encountered unexpected token解析错误,5.0开始如果碰到连续\n\n会把后面的语句截断导致在mybatis层出现Could not set parameters for mapping错误。 参考链接: https://github.com/JSQLParser/JSqlParser/issues/1988 mybatis-plus自3.5.3.2开始处理了框架内置注入的sql换行处理,但项目里自行编写的得语句需要自行处理。 - 注意: 3.5.10和3.5.10.1版本虽然处理项目里的换行情况,但对项目里使用单行注释(`--`或`#`这种语句处理无法支持),3.5.11版本后将不再处理,如果你需要处理连续换行语句可通过下面的方式进行处理。 方式一: ```java static { JsqlParserGlobal.setParserMultiFunc((sql)-> { String formatSql = CCJSqlParserUtil.sanitizeSingleSql(sql); return CCJSqlParserUtil.parseStatements(formatSql, JsqlParserGlobal.getExecutorService(), null); }); JsqlParserGlobal.setParserSingleFunc((sql)-> { String formatSql = CCJSqlParserUtil.sanitizeSingleSql(sql); return CCJSqlParserUtil.parse(formatSql, JsqlParserGlobal.getExecutorService(), null); }); } // 如果jsqlParser低于5.0,请把如下方法复制到自己工程里,代码来源JsqlParser5.0版本。 public static String sanitizeSingleSql(String sqlStr) { Pattern SQL_DELIMITER_SPLIT = Pattern.compile("((?:'[^']*+'|[^\\n])*+)"); StringBuilder builder = new StringBuilder(); Matcher matcher = SQL_DELIMITER_SPLIT.matcher(sqlStr); while(matcher.find()) { for(int i = 1; i <= matcher.groupCount(); ++i) { if (!matcher.group(i).isEmpty()) { builder.append("\n").append(matcher.group(i)); } } } return builder.toString(); } ``` 方式二: 开启mybatis的去除换行语句(通用性可能没那么好,无法处理单行注释--或#这样的) ```yaml mybatis-plus: configuration: shrink-whitespaces-in-sql: true ``` ## 代码生成器如何配置生成 XXXRepository 后续不再维护Service与Repository,建议不要在继续使用,如果需要生成,请按如下步骤将service转换为repository。 ```java AutoGenerator generator = new AutoGenerator(DATA_SOURCE_CONFIG); generator.packageInfo(new PackageConfig.Builder() //-- 转换开始---- .service("repository") .serviceImpl("repository.impl") //-- 转换结束---- .build()); generator.strategy( new StrategyConfig.Builder() //-- 转换开始---- .serviceBuilder().convertServiceFileName(entityName -> "I" + entityName + "Repository") .superServiceClass(IRepository.class).convertServiceImplFileName(entityName -> entityName + "Repository") .superServiceImplClass(CrudRepository.class) //-- 转换结束---- .build()); generator.execute(); ```