MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
JPA
Spring Data JPA, part of the larger Spring Data family, makes it easy to easily implement JPA based repositories. This module deals with enhanced support for JPA based data access layers. It makes it easier to build Spring-powered applications that use data access technologies.
Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that’s actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.
Features
Sophisticated support to build repositories based on Spring and JPA
Support for Querydsl predicates and thus type-safe JPA queries
Transparent auditing of domain class
Pagination support, dynamic query execution, ability to integrate custom data access code
Validation of @Query
annotated queries at bootstrap time
Support for XML based entity mapping
JavaConfig based repository configuration by introducing @EnableJpaRepositories
.
MybatisPlus
特性
无侵入 :只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小 :启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作 :内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用 :通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成 :支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式 :支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作 :支持全局通用方法注入( Write once, use anywhere )
内置代码生成器 :采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件 :基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库 :支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件 :可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件 :提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
框架结构
快速入门 1.创建对应数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 DROP TABLE IF EXISTS user ;CREATE TABLE user ( id BIGINT (20 ) NOT NULL COMMENT '主键ID' , name VARCHAR (30 ) NULL DEFAULT NULL COMMENT '姓名' , age INT (11 ) NULL DEFAULT NULL COMMENT '年龄' , email VARCHAR (50 ) NULL DEFAULT NULL COMMENT '邮箱' , PRIMARY KEY (id) ); DELETE FROM user ;INSERT INTO user (id, name, age, email) VALUES (1 , 'Jone' , 18 , 'test1@baomidou.com' ), (2 , 'Jack' , 20 , 'test2@baomidou.com' ), (3 , 'Tom' , 28 , 'test3@baomidou.com' ), (4 , 'Sandy' , 21 , 'test4@baomidou.com' ), (5 , 'Billie' , 24 , 'test5@baomidou.com' );
2.初始化项目(SpringBoot)
添加依赖
引入 Spring Boot Starter 父工程:
1 2 3 4 5 6 <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.6.4</version > <relativePath /> </parent >
引入 spring-boot-starter
、spring-boot-starter-test
、mybatis-plus-boot-starter
、h2
依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.5.1</version > </dependency > <dependency > <groupId > com.h2database</groupId > <artifactId > h2</artifactId > <scope > runtime</scope > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.0.5</version > </dependency >
1 2 3 4 5 spring.datasource.username =root spring.datasource.password =1234 spring.datasource.url =jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimeZone=GMT%2B8 spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.zero.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; }
1 2 3 4 5 6 7 8 9 10 11 package com.zero.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.zero.pojo.User;import org.springframework.stereotype.Repository;@Mapper @Repository public interface UserMapper extends BaseMapper <User > { }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.zero;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.zero.mapper") @SpringBootApplication public class MybatisPlusDemoApplication { public static void main (String[] args) { SpringApplication.run(MybatisPlusDemoApplication.class, args); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.zero;import com.zero.mapper.UserMapper;import com.zero.pojo.User;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest class MybatisPlusDemoApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads () { List<User> users = userMapper.selectList(null ); users.forEach(System.out::println); } }
配置日志 1 mybatis-plus.configuration.log-impl =org.apache.ibatis.logging.stdout.StdOutImpl
主键生成策略 1 2 3 4 5 6 7 8 9 10 11 12 @Test public void insertTest () { User user = new User(); user.setName("Kate" ); user.setAge(11 ); user.setEmail("2323256@qq.com" ); int result = userMapper.insert(user); System.out.println(result); System.out.println(user); }
分布式系统唯一ID生成方案汇总
1.数据库自增长序列或字段
最常见的方式,全数据库唯一。
优点:
缺点:
不同数据库语法和实现不同,数据库迁移或多数据库版本支持时需要处理
在单个数据库或读写分离或一主多从的情况下,只有一个主库可以生成。有单点故障的风险
不适用于高并发环境
并非一定连续,如MySQL中当生成新ID的事务回滚,那么后续的事务不会再用该ID。为了保证连续,必须在事务结束后才能生成ID,影响性能
2.UUID
通用唯一识别码 (U niversally U nique Id entifier)是用于计算机体系中以识别信息的一个128位标识符。根据标准方法生成,不依赖中央机构的注册和分配,UUID具有唯一性,这与其他大多数编号方案不同。重复UUID码概率接近零,可以忽略不计。
可以利用数据库也可以利用程序生成。UUID是由32个的16进制数字组成,所以每个UUID的长度是128位。
UUID 通常用作唯一键的数据库表。MySQL 提供了一个 UUID 函数,它生成标准版本1 UUID(日期时间和MAC地址)。当 UUID 用作主键时,版本3、4和5 UUID 的随机性以及版本1和2 UUID 内的字段的排序可能会产生数据库位置或性能问题。
优点:
缺点:
没有排序,无法保证递增
往往使用字符串存储,查询效率较低
需要存储空间比较大
传输数据量大
不可读(UUID to Int64 )
3.Redis生成ID
当使用数据库生成ID性能不够,可以尝试使用Redis生成ID。主要依赖于Redis是单线程的,可以生成全局唯一的ID。使用用Redis的原子操作INCR和INCRBY来实现。
优点:
不依赖于数据库,灵活方便,且性能优于数据库。
数字ID天然排序,便于分页或者排序。
缺点:
需要引入Redis,增加系统复杂度。
需要编码和配置
4.snowflake 雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果为long型的ID。
使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号,最后还有一个永远是0的符号位。
优点:
不依赖于数据库,灵活方便,且性能优于数据库
ID按照时间在单机上是递增的
缺点:
1 2 3 4 5 6 7 8 9 public enum IdType { AUTO(0 ), NONE(1 ), INPUT(2 ), ID_WORKER(3 ), UUID(4 ), ID_WORKER_STR(5 ); }
1.实体字段上加上@TableID
1 2 @TableId(type= IdType.AUTO) private Long id;
2.数据库字段设置为对应类型(如自增)
sqlyog->对应数据库和表->改变表
CRUD
1 2 3 4 5 6 7 8 9 10 @Test public void updateTest () { User user = new User(); user.setId(1L ); user.setName("K" ); user.setAge(21 ); user.setEmail("230000@qq.com" ); int result = userMapper.updateById(user); System.out.println(result); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void selectByIdTest () { User user = userMapper.selectById(1L ); System.out.println(user); } @Test public void selectByBatchID () { List<User> users = userMapper.selectBatchIds(Arrays.asList(1 ,2 ,3 )); users.forEach(System.out::println); } @Test public void selectByBatchIdsTest () { HashMap<String,Object> map = new HashMap<>(); map.put("name" ,"Zus" ); map.put("age" ,13 ); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void deleteByIdTest () { int result = userMapper.deleteById(8L ); System.out.println(result); } @Test public void deleteByBatchTest () { int result = userMapper.deleteBatchIds(Arrays.asList(6L ,7L )); } @Test public void deleteByMapTest () { HashMap<String,Object> map = new HashMap<>(); map.put("name" ,"Yi" ); int result = userMapper.deleteByMap(map); }
自动填充 1.数据库级别(不推荐)
在表中新增字段create_time、update_time
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.util.Date;@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type= IdType.AUTO) private Long id; private String name; private Integer age; private String email; private Date createTime; private Date updateTime; }
2.代码级别
MyBatis-Plus 3.0.5
在表中新增字段create_time、update_time
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type= IdType.AUTO) private Long id; private String name; private Integer age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.zero.handler;@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill (MetaObject metaObject) { log.info("start insert fill ...." ); this .setFieldValByName("createTime" ,new Date(),metaObject); this .setFieldValByName("updateTime" ,new Date(),metaObject); } @Override public void updateFill (MetaObject metaObject) { log.info("start update fill ...." ); this .setFieldValByName("updateTime" ,new Date(),metaObject); } }
MyBatis-Plus 3.3.0(官方)
1 2 3 4 5 6 <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.3.0</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type= IdType.AUTO) private Long id; private String name; private Integer age; private String email; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill (MetaObject metaObject) { log.info("start insert fill ...." ); this .strictInsertFill(metaObject, "createTime" , LocalDateTime.class, LocalDateTime.now()); this .strictUpdateFill(metaObject, "updateTime" , LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill (MetaObject metaObject) { log.info("start update fill ...." ); this .strictUpdateFill(metaObject, "updateTime" , LocalDateTime.class, LocalDateTime.now()); } }
乐观锁与悲观锁
在关系数据库管理系统里,乐观并发控制 (乐观锁,Optimistic Concurrency Control,OCC)是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。
乐观并发控制多数用于数据争用不大、冲突较少的环境中,这种环境中,偶尔回滚事务的成本会低于读取数据时锁定数据的成本,因此可以获得比其他并发控制方法更高的吞吐量。
乐观并发控制的事务包括以下阶段:
读取 :事务将数据读入缓存,这时系统会给事务分派一个时间戳。
校验 :事务执行完毕后,进行提交。这时同步校验所有事务,如果事务所读取的数据在读取之后又被其他事务修改,则产生冲突,事务被中断回滚。
写入 :通过校验阶段后,将更新的数据写入数据库。
在关系数据库管理系统里,悲观并发控制 (悲观锁 ,Pessimistic Concurrency Control,PCC)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作读某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。
悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。
Optimistic vs Pessimistic locking
Lost Update anomaly:
由于Bob改变了账号余额,Alice并不能提到40(Alice查询账号count余额大于40故发起提款请求,Alice查询和取款工程中Bob实际已经完成了查询和取款操作)
悲观锁通过对帐户采取共享或读取锁从而防止 Bob 更改帐户。
只有Alice提交她的事务并释放读锁定之后,Bob 才会恢复并应用更改。在 Alice 释放读取锁之前,Bob 的 UPDATE 会阻塞。
乐观锁定允许发生冲突,但在version更改时,来自 Alice 的 UPDATE 操作时会检测到冲突。
每次执行 UPDATE 或 DELETE 时,version列都会递增,用于 UPDATE 和 DELETE 语句的 WHERE 子句中,需要在执行 UPDATE 或 DELETE 之前发出 SELECT 并读取当前值。
OptimisticLockerInnerInterceptor
取出记录时,获取当前 version
更新时,带上这个 version
执行更新时, set version = newVersion where version = oldVersion(确保查询到修改过程中没有其他人进行修改,即当要更新一条记录的时候,希望这条记录没有被别人更新 )
如果 version 不对,就更新失败
1.数据库添加version字段
2.实体类添加对应字段
1 2 @Version private Integer version;
3.配置插件
Mybatis-Plus 3.0.5
1 2 3 4 5 6 7 8 @EnableTransactionManagement @Configuration public class MybatisPlusConfig { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor () { return new OptimisticLockerInterceptor(); } }
Mybatis-Plus 3.5.1
1 2 3 4 5 6 7 8 9 10 @EnableTransactionManagement @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor () { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
4.测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Test public void optimisticLockerTest () { User user = userMapper.selectById(1L ); user.setName("adc" ); user.setEmail("df@qq.com" ); userMapper.updateById(user); } @Test public void optimisticLockerTest2 () { User user = userMapper.selectById(1L ); user.setName("Aone" ); user.setEmail("Aone@qq.com" ); User user2 = userMapper.selectById(1L ); user2.setName("Bone" ); user2.setEmail("Bone@qq.com" ); userMapper.updateById(user2); userMapper.updateById(user); }
分页 Mybatis-plus 3.0.5
1.配置分页插件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @MapperScan("com.zero.mapper") @EnableTransactionManagement @Configuration public class MybatisPlusConfig { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor () { return new OptimisticLockerInterceptor(); } @Bean public PaginationInterceptor paginationInterceptor () { return new PaginationInterceptor(); } }
2.测试
1 2 3 4 5 6 7 8 9 @Test public void limitPageTest () { Page<User> page = new Page<>(2 ,5 ); userMapper.selectPage(page,null ); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
逻辑删除 逻辑删除 (logical deletion),又被称软删除 、假删除 ,是一种数据库操作,使用标记将数据标为不可用,而不从数据库删除数据本身。使用适当的方法可恢复被删除的文件。
1.数据库中增加字段
2.实体类增加字段
1 2 @TableLogic private Integer deleted;
Mybatis-plus 3.0.5
3.配置插件
1 2 3 4 @Bean public ISqlInjector iSqlInjector () { return new LogicSqlInjector(); }
1 2 mybatis-plus.global-config.db-config.logic-delete-value =1 mybatis-plus.global-config.db-config.logic-not-delete-value =0
4.测试
1 2 3 4 5 @Test public void deleteByIdTest () { int result = userMapper.deleteById(1L ); System.out.println(result); }
性能分析器
性能分析拦截器,用于输出每条SQL语句及其执行时间
Mybatis-plus3.0.5
1。配置插件
1 2 3 4 5 6 7 8 @Bean @Profile({"dev","test"}) public PerformanceInterceptor performanceInterceptor () { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(1000 ); performanceInterceptor.setFormat(true ); return performanceInterceptor; }
1 spring.profiles.active =dev
2.测试
条件构造器(Wrapper) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 @SpringBootTest public class WrapperTest { @Autowired private UserMapper userMapper; @Test void wrapperTest1 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .isNotNull("name" ) .isNotNull("email" ) .ge("age" ,12 ); userMapper.selectList(wrapper).forEach(System.out::println); } @Test void wrapperTest2 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .eq("name" ,"Tom" ); User user = userMapper.selectOne(wrapper); System.out.println(user); } @Test void wrapperTest3 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.between("age" ,12 ,21 ); Integer count = userMapper.selectCount(wrapper); System.out.println(count); } @Test void wrapperTest4 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .notLike("name" ,"T" ) .likeRight("email" ,"5" ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } @Test void wrapperTest5 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.inSql("id" ,"select id from user where id<4" ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } @Test void wrapperTest6 () { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.orderByDesc("id" ); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } }
代码自动生成器 Mybatis-plus-generator
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
Mybatis-Plus 3.5.1 以下
1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > org.apache.velocity</groupId > <artifactId > velocity-engine-core</artifactId > <version > 2.0</version > </dependency > <dependency > <groupId > com.spring4all</groupId > <artifactId > spring-boot-starter-swagger</artifactId > <version > 1.5.1.RELEASE</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public class MyAutoGenerator { public static void main (String[] args) { AutoGenerator mpg = new AutoGenerator(); GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir" ); gc.setOutputDir(projectPath + "/src/main/java" ); gc.setAuthor("ZERO" ); gc.setOpen(false ); gc.setFileOverride(false ); gc.setServiceName("%sService" ); gc.setIdType(IdType.ID_WORKER); gc.setDateType(DateType.ONLY_DATE); gc.setSwagger2(true ); mpg.setGlobalConfig(gc); DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimeZone=GMT%2B8" ); dsc.setDriverName("com.mysql.cj.jdbc.Driver" ); dsc.setUsername("root" ); dsc.setPassword("1234" ); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); PackageConfig pc = new PackageConfig(); pc.setModuleName("blog" ); pc.setParent("com.zero" ); pc.setEntity("entity" ); pc.setMapper("mapper" ); pc.setService("service" ); pc.setController("controller" ); mpg.setPackageInfo(pc); StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("user" ); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true ); strategy.setLogicDeleteFieldName("deleted" ); TableFill gmtCreate = new TableFill("create_time" , FieldFill.INSERT); TableFill gmtModified = new TableFill("update_time" , FieldFill.INSERT_UPDATE); ArrayList<TableFill> tableFills = new ArrayList<>(); tableFills.add(gmtCreate); tableFills.add(gmtModified); strategy.setTableFillList(tableFills); strategy.setVersionFieldName("version" ); strategy.setRestControllerStyle(true ); strategy.setControllerMappingHyphenStyle(true ); mpg.setStrategy(strategy); mpg.execute(); } }