MyBatis Plus 基础

本文将介绍 MyBatis Plus 的基本用法。

一、注解

具体请看:

注解 | MyBatis-Plus

  • @TableName:用于描述实体类对应的表名
  • @TableId:用于描述主键
  • @TableField:用于描述字段
  • @OrderBy:用于指定排序规则

二、Mapper 增删改查

1. Insert

插入一条数据:

1
int insert(T entity);

2. Delete

根据 ID,删除记录:

1
int deleteById(Id id);

根据 ID 集合,批量删除记录:

1
int deleteBatchIds(Collection<Id> idList);

根据 Map,删除记录:

Map 中,key 为字段名、value 为字段值,将会删除所有与 Map 相符合的记录。

1
int deleteByMap(Map<字段名, 字段值> columnMap);

根据条件构造器,删除记录:

1
int delete(Wrapper<T> wrapper);

3. Update

根据实体类中的 ID,更新记录:

1
int updateById(T entity);

根据条件构造器,更新记录:

根据 wrapper 匹配记录,将所有匹配到的记录根据 entity 更新。

1
int update(T entity, Wrapper<T> wrapper);

4. Select

根据 ID,查询一条记录:

1
T selectById(Id id);

根据条件构造器,查询一条记录:

1
T selectOne(Wrapper<T> wrapper);

根据 ID 集合,查询所有记录:

1
List<T> selectBatchIds(Collection<Id> idList);

根据 Map,查询所有记录:

Map 中,key 为字段名、value 为字段值,将会查询所有与 Map 相符合的记录。

1
List<T> selectByMap(Map<字段名, 字段值> columnMap);

根据条件构造器,查询所有记录:

将查询结果中的每一行封装进对象之中,以对象集合的形式返回。

1
List<T> selectList(Wrapper<T> wrapper);

根据条件构造器,查询所有记录,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 集合的形式返回。

1
List<Map<字段名, 字段值>> selectMaps(Wrapper<T> wrapper);

根据条件构造器,查询所有记录,以第一个字段的集合返回:

只获取查询结果中每一行的第一个字段,以集合的形式返回。

1
List<Object> selectObjs(Wrapper<T> wrapper);

根据分页条件和条件构造器,查询所有记录:

将查询结果中的每一行封装进对象之中。

1
IPage<T> selectPage(IPage<T> page, Wrapper<T> wrapper);

根据分页条件和条件构造器,查询所有记录,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中。

1
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> wrapper);

根据条件构造器,查询符合条件的记录数:

1
Long selectCount(Wrapper<T> wrapper);

三、Service 增删改查

1. Save

插入一条记录:

1
boolean save(T entity);

插入多条记录:

默认每批最多提交 1000 条。

1
boolean saveBatch(Collection<T> entityList);

插入多条记录:

指定每批提交的个数。

1
boolean saveBatch(Collection<T> entityList, int batchSize);

2. SaveOrUpdate

插入或更新记录:

若实体类中的 id 在数据库中没有对应记录,则插入记录,否则更新记录。

1
boolean saveOrUpdate(T entity);

更新或插入或更新记录:

首先根据条件构造器尝试更新记录;

如果更新不成功,则尝试插入或更新记录。

1
boolean saveOrUpdate(T entity, Wrapper<T> wrapper);

源码如下:

1
2
3
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return update(entity, updateWrapper) || saveOrUpdate(entity);
}

3. Remove

根据 ID,删除记录:

1
boolean removeById(Id id);

根据 ID 集合,批量删除记录:

1
boolean removeByIds(Collection<Id> idList);

根据 Map,删除记录:

Map 中,key 为字段名、value 为字段值,将会删除所有与 Map 相符合的记录。

1
boolean removeByMap(Map<字段名, 字段值> columnMap);

根据条件构造器,删除记录:

1
boolean remove(Wrapper<T> wrapper);

4. Update

根据实体类中的 ID,更新记录:

1
boolean updateById(T entity);

根据实体类中的 ID,批量更新记录:

默认每批最多提交 1000 条。

1
boolean updateBatchById(Collection<T> entityList);

根据实体类中的 ID,批量更新记录:

指定每批提交的个数。

1
boolean updateBatchById(Collection<T> entityList, int batchSize);

根据条件构造器,更新记录:

根据 wrapper 匹配记录,将所有匹配到的记录根据 entity 更新。

1
boolean update(T entity, Wrapper<T> wrapper);

根据条件构造器,更新记录:

wrapper 需要设置 sqlset;

根据 wrapper 匹配记录,并根据 wrapper 更新。

1
boolean update(Wrapper<T> wrapper);

5. Get

根据 ID,查询一条记录:

1
T getById(ID id);

根据条件构造器,查询一条记录:

如果查询到多条记录将会抛出异常。

1
T getOne(Wrapper<T> wrapper);

根据条件构造器,查询一条记录:

throwEx 用于指定如果查询到多条记录时是否抛出异常。

1
T getOne(Wrapper<T> wrapper, boolean throwEx);

根据条件构造器,查询一条记录,以 Map 形式返回:

将查询结果(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 形式返回。

1
Map<String, Object> getMap(Wrapper<T> wrapper);

根据条件构造器,查询一条记录,返回为指定类型:

其中,

  • V:结果的类型
  • mapper:转换函数,将结果转换为 V 类型的数据
1
<V> V getObj(Wrapper<T> wrapper, Function<? super Object, V> mapper);

6. List

查询所有记录:

1
List<T> list();

根据 ID 集合,查询所有记录:

1
Collection<T> listByIds(Collection<Id> idList);

根据条件构造器,查询所有记录:

1
List<T> list(Wrapper<T> wrapper);

根据 Map,查询所有记录:

Map 中,key 为字段名、value 为字段值,将会查询所有与 Map 相符合的记录。

1
Collection<T> listByMap(Map<String, Object> columnMap);

查询所有记录,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 集合的形式返回。

1
List<Map<String, Object>> listMaps();

根据条件构造器,查询所有记录,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 集合的形式返回。

1
List<Map<String, Object>> listMaps(Wrapper<T> wrapper);

查询所有记录:

1
List<Object> listObjs();

源码:

1
2
3
default List<Object> listObjs() {
return listObjs(Function.identity());
}

其中,Function.identity() 为:

1
2
3
static <T> Function<T, T> identity() {
return t -> t;
}

它将始终返回其输入。

查询所有记录,返回为指定类型:

其中,

  • V:结果的类型
  • mapper:转换函数,将结果转换为 V 类型的数据
1
<V> List<V> listObjs(Function<? super Object, V> mapper);

根据条件构造器,查询所有记录:

1
List<Object> listObjs(Wrapper<T> wrapper);

源码:

1
2
3
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return listObjs(queryWrapper, Function.identity());
}

其中,Function.identity() 为:

1
2
3
static <T> Function<T, T> identity() {
return t -> t;
}

它将始终返回其输入。

根据条件构造器,查询所有记录:

其中,

  • V:结果的类型
  • mapper:转换函数,将结果转换为 V 类型的数据
1
<V> List<V> listObjs(Wrapper<T> wrapper, Function<? super Object, V> mapper);

7. Page

分页查询:

1
IPage<T> page(IPage<T> page);

根据条件构造器,分页查询:

1
IPage<T> page(IPage<T> page, Wrapper<T> wrapper);

分页查询,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 集合的形式返回。

1
IPage<Map<String, Object>> pageMaps(IPage<T> page);

根据条件构造器,分页查询,以 Map 形式返回:

将查询结果中的每一行(以 key 为字段名、value 为字段值的方式)封装进 Map 中,以 Map 集合的形式返回。

1
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> wrapper);

8. Count

查询总记录数:

1
int count();

根据条件构造器,查询总记录数:

1
int count(Wrapper<T> wrapper);

9. 链式查询

1
2
3
4
5
// 链式查询 普通
QueryChainWrapper<T> query();

// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
1
2
3
// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();

10. 链式修改

1
2
3
4
5
// 链式更改 普通
UpdateChainWrapper<T> update();

// 链式更改 lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
1
2
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);

四、条件构造器

具体请看:

条件构造器 | MyBatis-Plus

  • boolean condition:该参数表示条件是否生效。

    当 condition 为 false 时,该条件将不会出现在 SQL 中。

    可以在此处加入判断,从而实现动态增减条件

  • 类型为 boolean 的参数可以不出现,不出现时默认为 true

  • BiPredicate 是一个函数结果,它

1. allEq - 全等

1
allEq(boolean condition, Map<字段名, 字段值> params, boolean null2IsNull)
  • Map<字段名, 字段值> params:以 key 为字段名、value 为字段值,描述记录应该符合的状态
  • boolean null2IsNull
    • 为 true 时,当 map 中某个键值对的值为 null,对应的 SQL 将为 键 is null
    • 为 false 时,当 map 中某个键值对的值为 null,将不会有对应的 SQL

allEq({id:1,name:”老王”,age:null}) —> id = 1 and name = ‘老王’ and age is null

allEq({id:1,name:”老王”,age:null}, false) —> id = 1 and name = ‘老王’

1
allEq(boolean condition, BiPredicate<字段名, 字段值> filter, Map<字段名, 字段值> params, boolean null2IsNull) 
  • BiPredicate<字段名, 字段值> filter:过滤函数,根据字段名和字段值进行判断,根据判断结果确定字段对应的条件是否生效

    BiPredicate 是一个函数接口,它接收两个参数,并返回一个 boolean 值

  • Map<字段名, 字段值> params:以 key 为字段名、value 为字段值,描述记录应该符合的状态

  • boolean null2IsNull

    • 为 true 时,当 map 中某个键值对的值为 null,对应的 SQL 将为 键 is null
    • 为 false 时,当 map 中某个键值对的值为 null,将不会有对应的 SQL

allEq((k,v) -> k.indexOf(“a”) >= 0, {id:1,name:”老王”,age:null}) —> name = ‘老王’ and age is null

allEq((k,v) -> k.indexOf(“a”) >= 0, {id:1,name:”老王”,age:null}, false) —> name = ‘老王’

2. eq - 等于

1
eq(boolean condition, R 字段名, Object 值)

eq(“name”, “老王”) —> name = ‘老王’

3. ne - 不等于

1
ne(boolean condition, R 字段名, Object 值)

ne(“name”, “老王”) —> name <> ‘老王’

4. gt - 大于

1
gt(boolean condition, R 字段名, Object 值)

gt(“age”, 18) —> age > 18

5. ge - 大于等于

1
ge(boolean condition, R 字段名, Object 值)

ge(“age”, 18) —> age >= 18

6. lt - 小于

1
lt(boolean condition, R 字段名, Object 值)

lt(“age”, 18) —> age < 18

7. le - 小于等于

1
le(boolean condition, R 字段名, Object 值)

le(“age”, 18) —> age <= 18

8. between - 之间

1
between(boolean condition, R 字段名, Object 值1, Object 值2)

between(“age”, 18, 30) —> age between 18 and 30

9. notBetween - 不在之间

1
notBetween(boolean condition, R 字段名, Object 值1, Object 值2)

notBetween(“age”, 18, 30) —> age not between 18 and 30

10. like

1
like(boolean condition, R 字段名, Object 值)

like(“name”, “王”) —> name like ‘%王%’

11. notLike

1
notLike(boolean condition, R 字段名, Object 值)

notLike(“name”, “王”) —> name not like ‘%王%’

12. likeLeft

1
notLike(boolean condition, R 字段名, Object 值)

likeLeft(“name”, “王”) —> name like ‘%王’

13. likeRight

1
likeRight(boolean condition, R 字段名, Object 值)

likeRight(“name”, “王”) —> name like ‘王%’

14. isNull

1
isNull(boolean condition, R 字段名)

isNull(“name”) —> name is null

15. isNotNull

1
isNotNull(boolean condition, R 字段名)

isNotNull(“name”) —> name is not null

16. in

1
in(boolean condition, R 字段名, Collection<?> 值的集合)

in(“age”,{1,2,3}) —> age in (1,2,3)

1
in(boolean condition, R column, Object... 值的参数列表)

in(“age”, 1, 2, 3) —> age in (1,2,3)

17. notIn

1
notIn(boolean condition, R 字段名, Collection<?> 值的集合)

notIn(“age”,{1,2,3}) —> age not in (1,2,3)

1
notIn(boolean condition, R column, Object... 值参数列表)

notIn(“age”, 1, 2, 3) —> age not in (1,2,3)

18. inSql

1
inSql(boolean condition, R column, String inValue)
  • inValue:SQL 语句,将会被直接拼接至 SQL 中

inSql(“age”, “1,2,3,4,5,6”) —> age in (1,2,3,4,5,6)
inSql(“id”, “select id from table where id < 3”) —> id in (select id from table where id < 3)

19. notInSql

1
notInSql(boolean condition, R column, String inValue)
  • inValue:SQL 语句,将会被直接拼接至 SQL 中

notInSql(“age”, “1,2,3,4,5,6”) —> age not in (1,2,3,4,5,6)
notInSql(“id”, “select id from table where id < 3”) —> id not in (select id from table where id < 3)

20. groupBy

1
groupBy(boolean condition, R... 字段名参数列表)

groupBy(“id”, “name”) —> group by id,name

21. orderByAsc - 升序排序

1
orderByAsc(boolean condition, R... 字段名参数列表)

orderByAsc(“id”, “name”) —> order by id ASC,name ASC

22. orderByDesc - 降序排序

1
orderByDesc(boolean condition, R... 字段名参数列表)

orderByDesc(“id”, “name”) —> order by id DESC,name DESC

23. orderBy

1
orderBy(boolean condition, boolean isAsc, R... 字段名参数列表)

orderBy(true, true, “id”, “name”) —> order by id ASC,name ASC

24. having

1
having(boolean condition, String sqlHaving, Object... params)

having(“sum(age) > 10”) —> having sum(age) > 10

having(“sum(age) > {0}”, 11) —> having sum(age) > 11

25. func - 根据条件调用不同的方法

1
func(boolean condition, Consumer<Children> consumer)
  • consumer:函数,根据条件调用不同的方法

    Consumer 是一个函数式接口,表示接收一个参数且没有返回值的函数

func(i -> if(true) {i.eq(“id”, 1)} else {i.ne(“id”, 1)})

26. or

1
or(boolean condition)

or() 表示下一个方法是用 or 连接的(默认为 and 连接)。

or(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> or (name = ‘李白’ and status <> ‘活着’)

27. and

1
and(boolean condition, Consumer<Param> consumer)

and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> and (name = ‘李白’ and status <> ‘活着’)

28. nested

1
nested(boolean condition, Consumer<Param> consumer)

正常嵌套,不带 and 或 or

nested(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> (name = ‘李白’ and status <> ‘活着’)

29. apply

1
apply(boolean condition, String applySql, Object... params)

拼接 SQL

apply(“id = 1”) —> id = 1

apply(“date_format(dateColumn,’%Y-%m-%d’) = ‘2008-08-08’”) —> date_format(dateColumn,’%Y-%m-%d’) = ‘2008-08-08’”)

30. last

1
last(boolean condition, String lastSql)

在 SQL 的最后后拼接语句

31. exists

1
exists(boolean condition, String existsSql)

用 SQL 拼接 exists

exists(“select id from table where age = 1”) —> exists (select id from table where age = 1)

32. notExists

1
notExists(boolean condition, String notExistsSql)

用 SQL 拼接 not exists

notExists(“select id from table where age = 1”) —> not exists (select id from table where age = 1)

33. select

仅适用于 QueryWrapper

1
select(String... 字段名参数列表)

select(“id”, “name”, “age”)

1
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
  • entityClass:实体类的 class
  • Predicate<TableFieldInfo> predicate:过滤查询字段
1
select(Predicate<TableFieldInfo> predicate)
  • entityClass:实体类的 class
  • Predicate<TableFieldInfo> predicate:过滤查询字段
  • 用此方法时,需要保证 wrapper 中的 entity 属性有值

select(i -> i.getProperty().startsWith(“test”))

34. set

仅适用于 UpdateWrapper

1
set(boolean condition, String 字段名, Object 值)

set(“name”, “老李头”)

35. setSql

仅适用于 UpdateWrapper

1
setSql(String sql)

setSql(“name = ‘老李头’”)

36. lambda

仅适用于 QueryWrapper 和 UpdateWrapper

  • 在 QueryWrapper 中是获取 LambdaQueryWrapper
  • 在 UpdateWrapper 中是获取 LambdaUpdateWrapper

37. 自定义 SQL - 注解

如果希望自定义 SQL,则方法的参数应该为:

  • Wrapper ew
    
    1
    2
    3

    * ```java
    @Param(Constants.WRAPPER) Wrapper 任意名字

(1) 注解

1
2
@Select("select * from mysql_data ${ew.customSqlSegment}")
List<MysqlData> getAll(@Param(Constants.WRAPPER) Wrapper wrapper);

(2) XML

1
List<MysqlData> getAll(Wrapper ew);
1
2
3
<select id="getAll" resultType="MysqlData">
SELECT * FROM mysql_data ${ew.customSqlSegment}
</select>

38. Lambda

1
query().eq("id", value).one();

等价于:

1
lambdaQuery().eq(Entity::getId, value).one();

五、分页插件

1. 配置 - SpringBoot 方式

新建 MybatisPlus 配置类,增加方法如下:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}

}
  • @Configuration:对类注解,用于将类标记为自定义配置类
  • @Bean:对方法注解,方法将会产生一个 Bean,并交由 SpringBoot 管理

2. 自带的分页方法

  • 实例化 Page 对象,并传入将分页选项以参数方式传入

    1
    Page<User> page = new Page<>(当前页数,每页条数);
  • 调用分页查询方法,将 Page 对象传入,获取查询后返回的 Page 对象

  • 通过 Page 对象的 getRecords() 方法,获取查询出来的数据

1
2
3
4
5
Page<User> page = new Page<>(1, 2);
Page<User> page1 = userMapper.selectPage(page, null);
for (User user : Page1.getRecords()) {
System.out.println(user);
}

3. 自定义方法的分页

如果自定义方法也能实现分页效果,只需要将自定义方法的返回值设为 Page,并在参数的首位新增 Page 对象即可。

1
2
3
4
5
6
7
8
9
10
11
public interface UserMapper {//可以继承或者不继承BaseMapper
/**
* 查询
*
* @param page 分页对象,必须放在第一位
* @param state 状态
* @return 分页对象
*/
Page<User> select(Page<?> page, Integer state);

}
1
2
3
<select id="select" resultType="全限定类名">
SELECT id,name FROM user WHERE state=#{state}
</select>

六、主键生成

1. 生成方式

MyBatis Plus 默认使用雪花算法生成主键 ID,主键 ID 类型为 Long - BIGINT 或 String - VARCHAR。

snowflake 算法是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 类型的 ID 。

其核心思想:使用 41bit 作为毫秒数,10bit 作为机器的 ID(5bit 数据中心,5bit 机器ID),12bit 作为毫秒内的流水号(意味着每个节点在每个毫秒可以产生 4096 个ID),最后还有一个符号位,永远是0。

2. 主键策略

MyBatis Plus 默认有 5 种主键生成策略。

描述
AUTO 由数据库自增生成 ID
NONE 默认,会跟随全局
INPUT 自行输入 ID,或由填充插件生成
ASSIGN_ID 在插入数据库之前生成 ID,主键类型为 Number 或 String
ASSIGN_UUID 在插入数据库之前生成 UUID,主键类型为 String

当主键生成策略为 INPUT、ASSIGN_ID、ASSIGN_UUID

  • 如果设置主键策略为 Auto,当数据库支持主键递增且配置了主键递增,ID 将交由数据库,通过数据库自增的方式生成
  • 如果设置主键策略为 NONE 或不设置主键策略,则默认会使用 ASSIGN_ID 策略
  • 如果设置主键策略为 INPUT,则代表自行输入 ID,也可以通过”序列生成”
  • 如果设置主键策略为 ASSIGN_ID 和 ASSIGN_UUID,Mybatis Plus 将会使用雪花算法来自动生成 ID

3. 主键策略局部配置

在实体类中为主键注解 @TableId(type = 策略名) 来进行指定。

4. 主键策略全局配置

在 SpringBoot 配置文件中添加配置信息如下:

1
2
3
4
mybatis-plus:
global-config:
db-config:
id-type: 策略名

5. 主键策略 - INPUT

如果设置主键策略为 INPUT,则代表自行输入 ID,也可以通过”序列生成”

(1) 自行输入

如果自行数据,则传递给插入方法的实体对象应该自带 ID。

(2) 序列生成

对于某些有序列的数据库(如:Oracle、SQLServer 等),可以通过序列生成主键。

Mybatis Plus 支持 DB2、H2、Kingbase、Oracle 和 Postgre 数据库的序列生成

具体步骤如下:

  • 在数据库中新建序列

  • 配置序列生成插件

    • 法 1:在 MyBatis Plus 配置类中配置

      1
      2
      3
      4
      @Bean
      public IKeyGenerator keyGenerator() {
      return new OracleKeyGenerator();
      }
    • 法 2:使用 Mybatis Plus PropertiesCustomizer 自定义

      1
      2
      3
      4
      @Bean
      public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
      return plusProperties -> plusProperties.getGlobalConfig().getDbConfig().setKeyGenerator(new OracleKeyGenerator());
      }
  • 配置实体类:

    • 为类增加注解 @KeySequence(value = 序列名)
    • 为主键增加注解 @TableId(type = IdType.INPUT)
    1
    2
    3
    4
    5
    6
    7
    @KeySequence(value = 序列名)
    public class User {

    @TableId(type = IdType.INPUT)
    private String id;

    }

6. 自定义主键生成器

(1) 定义主键生成器类

新建类,实现 IdentifierGenerator 接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyIdGenerator implements IdentifierGenerator {
/**
* 生成Id
*
* @param entity 实体
* @return id
*/
@Override
public Number nextId(Object entity) {
return null;
}

/**
* 生成uuid
*
* @param entity 实体
* @return uuid
*/
@Override
public String nextUUID(Object entity) {
return IdentifierGenerator.super.nextUUID(entity);
}
}

(2) 配置主键生成器

  • 法 1:为主键生成器类加上注解,声明为 Bean,以便 Spring 扫描注入

  • 法 2:在 MyBatis Plus 配置类中新增 idGenerator() 方法,使方法返回主键生成器类的实例,并使用 @Bean 注解

    1
    2
    3
    4
    @Bean
    public IdentifierGenerator idGenerator() {
    return new MyIdGenerator();
    }
  • 法 3:使用 Mybatis Plus PropertiesCustomizer 自定义

    1
    2
    3
    4
    @Bean
    public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
    return plusProperties -> plusProperties.getGlobalConfig().getDbConfig().setKeyGenerator(new MyGenerator());
    }

参考