常见问题
本文档收录了 MyBatis-Plus 使用时遇到的各种常见问题,如果您在使用 MyBatis-Plus 的时候遇到了问题,请您优先查看本文档。
以下三种方式选择一种即可:
-
使用
transient
修饰 -
使用
static
修饰 -
使用
TableField
注解
使用 transient
修饰需要排除的父类属性
出现该异常通常是由于配置不正确或者 Mapper 没有被正确扫描到导致的。解决方案如下:
-
检查是否存在 jar 包冲突。
-
检查 Mapper.java 的扫描路径:
-
方法一:在
Configuration
类上使用注解MapperScan
-
方法二:在
Configuration
类中配置MapperScannerConfigurer
(查看示例)
-
-
检查是否指定了主键。如果未指定,将导致
selectById
相关 ID 无法操作。请使用注解@TableId
注解表 ID 主键。当然,@TableId
注解可以省略,但是你的主键必须叫 id(忽略大小写)。 -
不要使用原生的 SqlSessionFactory,请使用 MybatisSqlSessionFactory。
-
检查是否自定义了 SqlInjector,是否复写了
getMethodList()
方法。在该方法中是否注入了你需要的方法(可参考 DefaultSqlInjector)。 -
IDEA 默认的 build 步骤可能会导致 mapper 文件无法正常编译到对应的 resources 文件夹中。请检查 build 后相关资源文件夹是否有对应的 XML 文件。如果没有,请调整 IDEA 的 build 设置。推荐调整为 Maven 或 Gradle 的 build。
问题描述:指在 XML 中里面自定义 SQL,却无法调用。本功能同 MyBatis
一样需要配置 XML 扫描路径:
- Spring MVC 配置(参考mybatisplus-spring-mvc)
- Spring Boot 配置(参考mybatisplus-spring-boot)
-
对于
IDEA
系列编辑器,XML 文件是不能放在 java 文件夹中的,IDEA 默认不会编译源码文件夹中的 XML 文件,可以参照以下方式解决:- 将配置文件放在 resource 文件夹中
- 对于 Maven 项目,可指定 POM 文件的 resource
-
异常一:
MapperScan 需要排除 com.baomidou.mybatisplus.mapper.BaseMapper 类 及其 子类(自定义公共 Mapper),比如:
-
异常二:
原因:低版本不支持泛型注入,请升级 Spring 版本到 4+ 以上。
-
异常三:
版本引入问题:3.4.1 版本里没有,3.4.2 里面才有!
检查是不是用了long
而不是Long
!
JavaScript 无法处理 Java 的长整型 Long 导致精度丢失,具体表现为主键最后两位永远为 0,解决思路: Long 转为 String 返回
-
FastJson 处理方式
-
JackJson 处理方式
-
方式一
-
方式二
-
-
比较一般的处理方式:增加一个
public String getIdStr()
方法,前台获取idStr
FieldStrategy 有三种策略:
- IGNORED:忽略
- NOT_NULL:非 NULL,默认策略
- NOT_EMPTY:非空
当用户有更新字段为 空字符串 或者 null
的需求时,需要对 FieldStrategy
策略进行调整:
-
方式一:调整全局的验证策略
注入配置 GlobalConfiguration 属性 fieldStrategy
-
方式二:调整字段验证注解
根据具体情况,在需要更新的字段中调整验证注解,如验证非空:
-
方式三:使用
UpdateWrapper
(3.x)使用以下方法来进行更新或插入操作:
默认mysql驱动会把tinyint(1)字段映射为boolean: 0=false, 非0=true
MyBatis 是不会自动处理该映射,如果不想把tinyint(1)映射为boolean类型:
- 修改类型tinyint(1)为tinyint(2)或者int
- 需要修改请求连接添加参数
tinyInt1isBit=false
,如下:
原因:配了 2 个分页拦截器! 检查配置文件或者代码,只留一个!
insert 后主键会自动 set 到实体的 ID 字段,所以你只需要 getId() 就好
EntityWrapper.sqlSelect 配置你想要查询的字段
我们建议缓存放到 service 层,你可以自定义自己的 BaseServiceImpl 重写注解父类方法,继承自己的实现。
如果你按照 mybatis 的方式配置第三方二级缓存,并且使用 2.0.9 以上的版本,则会发现自带的方法无法更新缓存内容,那么请按如下方式解决(二选一):
1.在代码中 mybatis 的 mapper 层添加缓存注释,声明 implementation 或 eviction 的值为 cache 接口的实现类
2.在对应的 mapper.xml 中将原有注释修改为链接式声明,以保证 xml 文件里的缓存能够正常
配置 jdbcTypeForNull=NULL Spring Bean 配置方式:
yml 配置
在自定义 SQL 中,由于 Page 对象继承自 RowBounds,在 Mapper 中无法直接获取。为了解决这个问题,请考虑以下替代方案:
- 使用自定义的 Map 对象或者普通的 Java 对象来传递参数。
- 通过在方法参数中使用 @Param(“page”) int page, @Param(“size”) int size 来传递页码和每页大小。
这些方法可以帮助您在自定义 SQL 中正确传递参数,确保代码的顺利运行。
当使用 resultType="java.util.Map"
时,您可以通过以下步骤在 Spring Boot 中实现下划线自动转换为驼峰:
在您的 Spring Boot 项目中创建一个配置类。
通过这样配置,您就可以实现自动将 Map 中的下划线转换为驼峰形式。这样,在 MyBatis 查询结果映射到 Map 对象时,键名会自动进行转换,使得您在代码中更加便捷地访问数据。
您可以通过以下方式在 Wrapper 中使用 limit
限制 SQL 结果集:
这段代码会在 SQL 语句末尾添加 limit 1,以限制结果集返回的行数为 1。
将通用的批量插入操作放在 Service 层处理有以下原因:
- SQL 长度存在限制:处理海量数据时,单条 SQL 可能无法执行或者容易引起内存泄漏、JDBC 连接超时等问题。
- 不同数据库的单条 SQL 批量语法不一致,不利于通用性。
- 解决方案:采用循环预处理批量提交的方法。虽然性能比单条 SQL 插入稍慢,但可以解决上述问题。
如果您想使用单条 SQL 插入方案,可以自行注入选装方法 insertbatchsomecolumn,或查看SQL 注入器中提供的方法。
在 MyBatis Plus 3.x 中,不再提供自动识别关键字进行处理的功能。处理数据库关键字的方法有以下几种:
-
不同数据库对关键字的处理方式不同,因此很难维护。在数据库设计时,建议避免使用关键字作为字段名或表名。
-
如果必须使用关键字,可以通过在字段或表名前后添加反引号(`)来进行处理,如下所示:
综上所述,为了避免出现问题,建议尽量避免在数据库设计中使用关键字。
针对 MyBatis Plus 3.1.1 及更高版本出现的问题:
现象:在单元测试中没有问题,但是在启动服务器进行调试时出现该异常。
原因:在 3.1.1 版本及以后的版本中,针对字段缓存进行了优化,使用 .class
作为键来替换了原来的类名(className)。然而,当使用 dev-tools 时,可能会导致 .class
使用不同的类加载器加载,从而导致出现找不到属性的情况。
解决方案:移除 dev-tools 插件。这样可以避免使用不同的类加载器加载 .class
,从而解决该异常问题。
针对 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 版本之前不支持此特性,导致出现此异常。详细信息请参考相关问题。
解决方案:
- 将 Druid 数据源升级至 1.1.21 版本以上,以解决此问题。
- 如果无法升级 Druid 数据源,可以选择保持 MyBatis Plus 版本在 3.1.0 及之前的版本。
- 若要继续使用最新的 MyBatis Plus 版本,可以考虑更换其他兼容新版 JDBC 的数据源,以避免出现此异常。
如果您将 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 官方博客 的内容:
解决方案:
- 升级您的 JDBC 驱动至支持 JDBC 4.2 API 的版本。
- 如果无法升级 JDBC 驱动,可以考虑将 MyBatis Plus 版本回滚至 3.1.0 或之前的版本。
如果您在将 Spring Boot 版本从 2.2.0 升级到更高版本时遇到此问题,可能是由于以下原因:
现象:在本地启动时没有问题,但是将打成 war 包部署到服务器时出现此问题。
原因:在 Spring Boot 2.2.0 中存在构造器注入的问题,导致 MyBatis 的私有构造器无法正确绑定属性,进而导致依赖 MyBatis 的框架(如 MyBatis Plus)报错。详细信息请参考 相关 issue。此问题已在 Spring Boot 2.2.1 中得到修复。
解决方案:
- 将 Spring Boot 降级至 2.1.x 版本,或升级至 2.2.1 版本以上。建议直接升级至 Spring Boot 2.2.2 版本以获取更好的稳定性和修复。
现象:在开发工具中运行没有问题,但是将项目打包部署到服务器后,执行 Lambda 表达式时出现 ClassNotFoundException。
针对 MyBatis Plus 3.3.2 以下版本,如果在分离打包部署时出现 ClassNotFoundException 的问题,可能是因为在执行反序列化操作时,类加载器发生了错误。
解决方案:
- 去除
spring-boot-maven-plugin
插件进行打包,或者 - 升级至 MyBatis Plus 3.3.2 版本。您可以参考示例 分离打包 进行操作。
您可以通过以下两种方式来启用 MyBatis 内部的日志记录:
方式一:
在您的 application.yml
或 application.properties
文件中添加以下配置:
这将使用 MyBatis 内置的 StdOutImpl 日志记录实现将日志输出到控制台。
方式二:
在您的 application.yml
或 application.properties
文件中增加日志级别配置,以指定特定包的日志级别。例如:
这将指定 com.baomidou.example.mapper 包下的日志级别为 debug。您可以根据需要调整级别。
通过以上配置,您可以启用 MyBatis 内部的日志记录,并根据需要调整日志级别。
如果您想要在更新操作时对某个字段进行自增操作,您可以使用 MyBatis Plus 提供的 Wrapper
进行更新。以下是一种可行的解决方案:
这样可以在更新时对字段进行自增操作。请注意,需要在 setSql
方法中直接指定 SQL 更新语句。
如果您想要全局处理数据库关键词,可以使用 MyBatis Plus 提供的全局配置。以下是配置示例(以 MySQL 为例):
这样配置后,MyBatis Plus 将会在生成 SQL 语句时,对数据库字段名称使用反引号(“)进行包裹,以确保不与数据库关键词冲突。
需要注意的是:
- 如果您使用了
@TableField
注解,并希望保持全局格式化,需要设置参数keepGlobalFormat=true
。 - 您也可以在
@TableField
注解中直接指定固定格式的数据库关键词,例如@TableField("'status'")
。
通过以上配置,您可以全局处理数据库关键词,确保生成的 SQL 语句不会受到关键词影响。
如果您想要在 XML 中根据数据库类型选择不同的 SQL 片段,您可以使用 MyBatis Plus 提供的 database-id
参数。以下是配置示例(以 MySQL 为例):
这样配置后,MyBatis Plus 将会在执行 SQL 语句时,根据 database-id
参数选择不同的 SQL 片段。
您可以根据不同的写法在 XML 中进行判断:
- 使用变量
_databaseId
:
- 使用标签属性
databaseId
:
通过以上配置,您可以根据不同的数据库类型选择不同的 SQL 片段。
MyBatis Plus 不支持复合主键并强制使用唯一的 ID,这是出于以下考虑:
-
增加了表与表之间的相互依赖性:使用复合主键会使表与表之间的关系更加复杂,增加了维护和管理的难度。
-
增加了数据复杂的约束、规则:复合主键会增加数据的约束和规则,例如需要约束唯一性,而完全可以使用联合索引来实现。
-
增加了更新数据的限制:在更新数据时,需要更新所有复合主键的值,这增加了更新操作的限制和复杂性。
-
严重的数据冗余和更新异常问题:复合主键可能导致数据冗余和更新异常的问题,特别是在大型系统中,可能会出现更新异常的情况。
-
性能问题:使用复合主键时,查询某个 ID 时无法使用索引,会导致性能下降。
综上所述,虽然使用复合主键可以省去一个 ID 字段,但是这种做法的缺点大于优点,不建议也不推荐这样做。MyBatis Plus 坚持使用唯一的 ID,以保证数据管理的简单性、可维护性和性能。
-
初始化默认雪花ID导致
- 查看本机hostname
- 编辑系统hosts文件,将本机hostname写入至hosts文件
-
检查数据库连接池初始化
碰到过使用hikari在linux系统下启动缓慢
解决方案:
在java启动命令中指定 -Djava.security.egd=file:/dev/urandom把获取随机数的方式从 /dev/random改为/dev/urandom
示例: java -Djava.security.egd=file:/dev/urandom -jar xxxx.jar
- 原因:驱动配置不兼容
解决方案:驱动连接去掉
rewriteBatchedStatements=true
配置
- 原因:mybatis默认情况下, 当返回行的所有列都是空时(含属性无法自动映射), 默认返回 null
解决方案:配置returnInstanceForEmptyRow 为true
- 原因:mybatis默认情况下, 当返回 null 时,不会调用put方法
解决方案:配置callSettersOnNulls 为true