一、简介
1.1 特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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.2 通用的MP模板
1.2.1 pom依赖
<!--SpringBoot整合mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter-test</artifactId>
<version>3.4.3.4</version>
</dependency>
<!-- mybatisPlus 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<!-- mybatisPlus Velocity 模版引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<!-- mybatisPlus Freemarker 模版引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.29</version>
</dependency>
<!--连接mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
1.2.2MyBatisPlusConfig
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//注册乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
1.2.3application.yml
#数据库
spring:
datasource:
username: root
password: qing
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncodeing=utf-8
mybatis-plus:
configuration:
#日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 全局逻辑删除的实体字段名(,配置后可以不用在实体类字段上使用@TableLogic注解)
logic-delete-field: isDel
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
1.2.4 MyMetaObjectHandler
字段填充
@Slf4j
//必须使用@Component注解将handler注入到ioc容器中
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
//要填充的字段 填充值 metaObject
//注意 这里的第二个属性使用new Date() 则实体类对属性值必须是Date属性 不然会报错 如:private Date createTime;
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);
}
}
1.2.5 代码生成器
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gcf = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gcf.setOutputDir(projectPath + "/src/main/java");
gcf.setAuthor("卿帆");
gcf.setOpen(false);
// 是否覆盖
gcf.setFileOverride(false);
// 去Service的I前缀
gcf.setServiceName("%sService");
//设置主键策略 自增
gcf.setIdType(IdType.AUTO);
//日期类型
gcf.setDateType(DateType.ONLY_DATE);
//配置swagger文档
gcf.setSwagger2(true);
mpg.setGlobalConfig(gcf);
//2、设置数据源
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("qing");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
//只需要改实体类名字 和包名 还有 数据库配置即可
//pc.setModuleName("");
//父级包名
pc.setParent("com.qing");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
//要转换的数据表 可同时配置多个
strategy.setInclude("user");
// 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 自动lombok;
strategy.setEntityLombokModel(true);
//配置逻辑删除字段 与yml配置文件对应
strategy.setLogicDeleteFieldName("isDel");
// 自动填充配置
//创建时间
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);
// localhost:8080/hello_id_2
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
二、快速入门
2.1 建立User表 导入数据
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.2 初始化一个SpringBoot项目
1、导入依赖
导入mybatis-plus依赖后就不用导入mybatis依赖了
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
<!--连接mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
2、配置文件
spring:
datasource:
username: root
password: qing
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncodeing=utf-8
#mybatis内置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3、传统配置(不推荐使用)
controller+service+mapper+mapper.xml
4、plus配置
User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
UserMapper接口:
@Mapper
//使用mybatis-plus 只需要在mapper接口这里继承BaseMapper 所有基础的CRUD就不需要在编写xml文件了
public interface UserMapper extends BaseMapper<User> {
}
可以看到BaseMapper接口中给我们封装了所有的CRUD代码,方法接口如下图:
使用MapperScan注解扫描包下的所有接口:
@SpringBootApplication
@MapperScan("com.qing.mapper")
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
5、测试
@SpringBootTest
class MybatisPlusApplicationTests {
@Resource
UserMapper userMapper;
@Test
void contextLoads() {
User user = userMapper.selectById(1);
System.out.println(user);
// selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,不填写就是无任何条件
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
}
三、CRUD扩展
3.1 插入
调用封装的inset方法插入一个实体,当不插入id时,会自动生成一个long型的id,这个id还可能为负。这就是分布式系统的主键策略:雪花算法
@Test
void testInsert() {
User user = new User();
user.setAge(20);
user.setName("卿帆");
user.setEmail("2259");
userMapper.insert(user);
}
3.2 主键生成策略
在User实体类中的id字段上添加注解@TableId
public class User {
@TableId(type = IdType.*)
private Integer id;
}
1、IdType.ASSIGN_ID
雪花算法:保证id全球唯一
SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图:
![](https://img-blog.csdnimg.cn/20190402101612645.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MTM1Mjg3,size_16,color_FFFFFF,t_70#alt=img)
● 1位,不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0
● 41位,用来记录时间戳(毫秒)。
○ 41位可以表示个数字,
○ 如果只用来表示正整数(计算机中正数包含0),可以表示的数值范围是:0 至 ,减1是因为可表示的数值范围是从0开始算的,而不是1。
○ 也就是说41位可以表示个毫秒的值,转化成单位年则是%20%2F%20(1000%20%2060%20%2060%20%2024%20%20365)%20%3D%2069#card=math&code=%282%5E%7B41%7D-1%29%20%2F%20%281000%20%2A%2060%20%2A%2060%20%2A%2024%20%2A%20365%29%20%3D%2069)年
● 10位,用来记录工作机器id。
○ 可以部署在个节点,包括 5位datacenterId 和 5位workerId
○ 5位(bit)可以表示的最大正整数是,即可以用0、1、2、3、….31这32个数字,来表示不同的datecenterId或workerId
● 12位,序列号,用来记录同毫秒内产生的不同id。
○ 12位(bit)可以表示的最大正整数是,即可以用0、1、2、3、….4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号
SnowFlake可以保证:
● 所有生成的id按时间趋势递增
● 整个分布式系统内不会产生重复id(因为有datacenterId和workerId来做区分)
2、 IdType.AUTO
主键自增策略,数据库中的id字段也必须设置为自动递增
3、其余策略
public enum IdType {
AUTO(0), //自增
NONE(1), //未设置主键
INPUT(2), //手动输入id 必须自己set注入
ASSIGN_ID(3), //默认全局唯一(全球唯一) 雪花算法
ASSIGN_UUID(4); //全局唯一uuid
}
3.3 更新
@Test
void update(){
User user=new User();
user.setId(10);
user.setEmail("22594797");
userMapper.updateById(user);
}
@Test
void update2(){
User user=new User();
user.setId(10);
user.setAge(3);
user.setEmail("22594797");
userMapper.updateById(user);
}
自动拼接动态sql语句!!
3.4 自动填充
每个表中都应该带有更新时间和创建时间!这个操作可以自动化实现,方式有直接配置数据库和在代码中自动填充
3.4.1 数据库操作(不建议)
首先在数据库表中增加create_time和update_time字段,并需要勾选根据当前时间戳更新
User实体类中也添加对应的字段
private String createTime;
private String updateTime;
再次更新表中数据时就会自动填充!
3.4.2 代码操作
(1)在User实体类中的字段上添加 @TableField注解
public class User {
@TableId(type = IdType.AUTO)
private Integer 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;
}
@TableField注解属性:
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入时填充字段
*/
INSERT,
/**
* 更新时填充字段
*/
UPDATE,
/**
* 插入和更新时填充字段
*/
INSERT_UPDATE
}
(2)创建一个MyMetaObjectHandler处理器,设置自动填充属性
@Slf4j
//必须使用@Component注解将handler注入到ioc容器中
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
//要填充的字段 填充值 metaObject
//注意 这里的第二个属性使用new Date() 则实体类对属性值必须是Date属性 不然会报错 如:private Date createTime;
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);
}
}
3.5 乐观锁
实现方式
乐观锁实现方式:很乐观,认为任何操作都不会出现问题,出现问题时才会报错
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
会出现问题:在单线程下不会出现问题,但在多线程中,如果有一个线程A正在执行修改操作,他校验的version是1,但此时来了一个线程B。且抢先执行,修改数据后version变成了2,那么此时线程A的修改就会停止!!,最终数据只是线程B修改后的数据!!
(1)在数据库表中增加字段version,初始化为1,并在实体类中同步添加属性version
public class User {
//乐观锁注解
@Version
private Integer version;
}
(2)配置MyBatisPlusConfig组件
@Configuration
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
(3)单线程测试
修改用户信息
@Test
void testLock() {
User user = userMapper.selectById(1);
user.setName("qf");
userMapper.updateById(user);
}
修改时是带上了version字段的
数据库中的version版本号也会加一
(4)模拟多线程
@Test
void testLock() {
//模拟线程A修改数据
User user = userMapper.selectById(1);
user.setName("qf");
//模拟模拟线程B修改数据,且抢先执行
User user2=userMapper.selectById(1);
user.setName("qf2");
userMapper.updateById(user2);
//线程A在线程B之后执行
userMapper.updateById(user);
}
可以看到,数据库中的数据为线程B提交的数据,A线程执行修改失败!
说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
3.6 查询
3.6.1 普通查询
@Test
void testSelect(){
//批量查询
List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2,10,15));
userList.forEach(System.out::println);
//条件查询 map拼接
Map<String,Object> map=new HashMap<>();
map.put("name","qf2");
map.put("age",18);
List<User> userList1 = userMapper.selectByMap(map);
userList1.forEach(System.out::println);
}
3.6.2分页查询
使用MP内置的分页插件
配置拦截器:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
测试:
@Test
void testPage() {
//当前页 页面大小
Page<User> page = new Page<>(2, 5);
//查询
Page<User> userPage = userMapper.selectPage(page, null);
//将page中的所有数据转存到实体集合中,方便返回给前端
List<User> userList = userPage.getRecords();
userList.forEach(System.out::println);
}
3.7 删除
3.7.1 直接删除(不推荐)
直接删除数据库中的数据
@Test
void testDel() {
//删除
Map<String, Object> map = new HashMap<>();
map.put("age",18);
//根据id删除
userMapper.deleteById(100);
//批量删除
userMapper.deleteBatchIds(Arrays.asList(10, 20, 30));
//通过map条件删除
userMapper.deleteByMap(map);
}
3.7.2 逻辑删除
在数据库中添加is_del
逻辑删除字段,并在实体类中添加对应的isDel
属性,添加 @TableLogic注解;默认使用驼峰映射
public class User {
//逻辑删除
@TableLogic
private Integer isDel;
}
配置yml
mybatis-plus:
global-config:
db-config:
# 全局逻辑删除的实体字段名(,配置后可以不用在实体类字段上使用@TableLogic注解)
logic-delete-field: isDel #这里的isDel需和实体类中的isDel对应
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
测试
@Test
void testDel2() {
/*配置了逻辑删除字段后,就无法在通过实体类来修改删除字段的值
User user = new User();
user.setId(1);
user.setIsDel(1);
userMapper.updateById(user);
*/
//直接调用deleteById方法就行
userMapper.deleteById(1);
System.out.println(userMapper.selectById(1));
}
四、条件构造器
@Test
void testWrapper1(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询姓名不为空,年龄大于18的所有用户
wrapper
.isNotNull("name")
.ge("age",18);
List<User> userList = userMapper.selectList(wrapper);
//查询name等于qf的指定用户
wrapper.eq("name","qf");
userMapper.selectOne(wrapper);
//查询age等于20的所有用户
wrapper.eq("age",20);
List<User> userList2 = userMapper.selectList(wrapper);
//查询age在20-30之间的用户
wrapper.between("age",20,30);
//模糊查询 查询name中不包含e 且邮箱是以t开头的所有用户
wrapper
.notLike("name","a")
//likeRight是以**开头,对右边迷糊查询,likeLeft则以**结尾对左边模糊查询
.likeRight("email","t");
List<User> userList = userMapper.selectList(wrapper);
//查询id为1 2 3中任意一个的用户列表
wrapper.in("id",Arrays.asList(1,2,3));
List<User> userList = userMapper.selectList(wrapper);
//groupBy orderByAsc orderByDesc having or and
}
五、自动生成器(重要)
- dao、pojo、service、controller都自动编写完成!
- AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、
- Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
- 只需要改实体类名字 和包名 还有 数据库配置即可
pom依赖:
注:这是旧版生成器,mybatis-plus-generator包的版本必须是3.5.0以下的,如果使用3.5.0以上的则需要使用新版生成器
<!-- mybatisPlus 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<!-- mybatisPlus Velocity 模版引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<!-- mybatisPlus Freemarker 模版引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.29</version>
</dependency>
方法:
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gcf = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gcf.setOutputDir(projectPath + "/src/main/java");
gcf.setAuthor("卿帆");
gcf.setOpen(false);
// 是否覆盖
gcf.setFileOverride(false);
// 去Service的I前缀
gcf.setServiceName("%sService");
//设置主键策略 自增
gcf.setIdType(IdType.AUTO);
//日期类型
gcf.setDateType(DateType.ONLY_DATE);
//配置swagger文档
gcf.setSwagger2(true);
mpg.setGlobalConfig(gcf);
//2、设置数据源
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("qing");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
//只需要改实体类名字 和包名 还有 数据库配置即可
//pc.setModuleName("");
//父级包名
pc.setParent("com.qing");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
//要转换的数据表 可同时配置多个
strategy.setInclude("user");
// 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 自动lombok;
strategy.setEntityLombokModel(true);
//配置逻辑删除字段
strategy.setLogicDeleteFieldName("isDel");
// 自动填充配置
//创建时间
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);
// localhost:8080/hello_id_2
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute(); //执行
}