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();
```