一、简述
简称MP,是在Mybatis的基础上进行增强,用户简化开发,提高效率。只做增强不做改变
支持
主键自动生成
、内置代码生成器
、内置分页插件
官网:MyBatis-Plus
二、快速开始
2.1 设计表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(11) NULL DEFAULT NULL, `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_user -- ---------------------------- INSERT INTO `t_user` VALUES (1, 'zs', '1234', '张三', 14, '北京'); INSERT INTO `t_user` VALUES (2, 'ls', '1234', '李四', 15, '河南'); SET FOREIGN_KEY_CHECKS = 1;
2.2 添加依赖
com.baomidou mybatis-plus-boot-starter 3.5.1 2.3 配置数据源
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/xxx username: root password: 1234
2.4 创建POJO
@Data @AllArgsConstructor @NoArgsConstructor @TableName("t_user") public class User { private Integer id; private String userName; private String password; private String nickName; private Integer age; private String address; }
2.5 创建Mapper接口
创建的Mapper接口去继承
BaseMapper
,泛型为POJO的类型public interface UserMapper extends BaseMapper
{ } 2.6 创建启动类
在启动类上添加
@MapperScan
注解,扫描Mapper接口所在的包@SpringBootApplication @MapperScan("com.jiuxiao.mapper") public class MPApp { public static void main(String[] args) { SpringApplication.run(MPApp.class,args); } }
2.7 编写测试方法
@SpringBootTest public class MPTest { @Autowired UserMapper userMapper; @Test void testSelectAll() { List
users = userMapper.selectList(null); System.out.println(users); } } 三、常用设置
3.1 日志打印
在控制台中打印操作的SQL语句
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.2 设置表映射规则
默认情况下MP在操作表名时,操作的是类名,如果类名和表名不一致就需要进行手动设置映射规则
① 单个设置
在实体类上添加
@TableName
注解,声明数据库表名@TableName("t_user") public class User { // ... }
② 全局设置
如果每个表的前缀都是
t_
,需要在每一个实体类上添加注解,比较频繁。可以使用以下配置mybatis-plus: global-config: db-config: table-prefix: t_
3.3 开启字段和属性的驼峰映射
从经典数据库列名A_COLUMN映射到经典Java属性名aColumn。
举例:
字段名为
user_name
,自动映射成userName
使用前提:
SQL中的字段名:全部小写,每个单词之间使用下划线分割
java中的属性名:首字母小写,其余单词首字母大写
该配置默认是开启的,无需任何配置
mybatis-plus: configuration: map-underscore-to-camel-case: true
3.4 字段和属性映射
MP中默认操作的字段名为实体类中的属性名,如果字段名和属性名不一致,需要手动映射
在实体类的属性上添加
@TableField
注解,声明表中字段名public class User { @TableField("user_name") private String userName; @TableField("nick_name") private String nickName; }
3.5 主键生成策略
AUTO
使用数据库中的自增策略,前提是表中主键声明了自增
NONE
默认策略(没有设置主键类型),使用雪花算法生成一个10位的数字
INPUT
手动给主键赋值,否则表中字段值为
null
ASSING_ID
当实体类中的主键属性值为
null
时,使用雪花算法分配ID【当前主键类型必须是Long和Integer和String】
ASSING_UUID
当实体类中的主键属性值为
null
时,使用UUID分配ID【当前主键类型必须是String】① 单个设置
在属性上添加
@TableId
注解,声明是一个主键
value:对应的是表中的主键字段名,如果字段名为
id
,该属性可以省略type:是一个枚举类型,声明主键生成策略
public class User { @TableId(value = "id",type = IdType.xxx) private Integer id; }
② 全局设置
如果每个表中的主键生成策略一致,可以使用全局配置
mybatis-plus: global-config: db-config: id-type: auto
四、CRUD
4.1 增加
传入实体类对象,增加之后通过
getter
方法可以获取主键值@Test void testInsert() { User user = new User(null, "ww", "4444", "王五", 16, "河北"); userMapper.insert(user); System.out.println("增加之后的主键 --> "+user.getId()); }
4.2 查询
根据
id
查询@Test void testSelectById() { User user = userMapper.selectById(1); System.out.println(user); }
多条件查询
@Test void testSelectByMap() { Map
map = new HashMap<>(); map.put("age",14); map.put("address","北京"); List list = userMapper.selectByMap(map); System.out.println(list); }
批量查询
@Test void testSelectBatch() { List
ids = Stream.of(2, 3).collect(Collectors.toList()); List users = userMapper.selectBatchIds(ids); System.out.println(users); } 4.3 更新
只更属性值不为
null
的字段,如果类型为基本数据类型,相对应的字段将会被修改成默认值比如
int
默认值为0,对应的字段值将会被修改成0@Test void testUpdate() { User user = new User(); user.setId(1); user.setAddress("河北"); user.setAge(66); userMapper.updateById(user); }
4.4 删除
根据
id
删除@Test void testDeleteById() { userMapper.deleteById(3); }
多条件删除
也可以传入对象
@Test void testDeleteByMap() { Map
map = new HashMap<>(); map.put("nick_name","李四"); map.put("user_name","ls"); userMapper.deleteByMap(map); }
批量删除
@Test void testDeleteBatch() { List
ids = Stream.of(1, 2).collect(Collectors.toList()); userMapper.deleteBatchIds(ids); } 五、条件构造器Wrapper
5.1 概述
在操作数据库中会牵扯到很多条件,所以MP提供了一个强大的条件构造器
Wrapper
,使用它可以让我们非常方便的构造条件继承体系:
在其子类
AbstractWrapper
中提供了很多构建Where条件的方法
AbstractWrapper
的子类QueryWrapper
中提供了用于针对SELECT语句的select
方法,可以设置只查询哪些字段
AbstractWrapper
的子类UpdateWrapper
中提供了用户针对SET语句的set
方法,可以设置只更新哪些字段5.2 AbstractWrapper中常用方法
eq
等于 =
例:
eq(name,"张三")
-->name = '张三'
allEq
allEq(Map
params) allEq(Map params, boolean null2IsNull) allEq(boolean condition,BiPredicate filter, Map params, boolean null2IsNull) 参数说明
params:
key
为数据库中的字段名,value
是条件null2IsNull:为
true
时,map
集合中value
为null
的调用isNull方法;为false
时则忽略value
为null
的filter:过滤函数,是否允许字段传入比对条件中
例
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 = '张三'
allEq((k,v)->k.indexOf('a') >= 0,{id : 1,name : "张三",age : null},false)
-->name = '张三'
ne
不等于 <>
例:
ne("name","李四")
-->name <> '李四'
gt
大于 >
例:
gt("age",18)
-->age > 18
ge
大于等于 >=
例:
ge("age",18)
-->age >= 18
lt
小于 <
例:
lt("age",18)
-->age < 18
le
小于等于 <=
例:
le("age",18)
-->age <= 18
between
BETWEEN 值1 AND 值2
例:
between("age",15,40)
-->age BETWEEN 15 AND 40
like
LIKE %值%
例:
like("name","王")
-->name like '%王%'
likeLeft
LIKE %值
例:
likeLeft("name","三")
-->name like '%三'
likeRight
LIKE 值%
例:
likeRight("name","李")
-->name like '李%'
isNull
字段 IS NULL
例:
inNull("address")
-->address is null
isNotNull
字段 IS NOT NULL
例:
isNotNull("id")
-->id is not null
in
字段 IN (v0,v1)
例:
in("id",1,2,3)
-->id in (1, 2, 3)
① 示例
需求:查询address以"河"开头、成年的用户信息
SQL语句
select * from t_user where address like '河%' and age >= 18
使用Wrapper查询
@Test void testWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.likeRight("address","河"); wrapper.ge("age",18); List users = userMapper.selectList(wrapper); System.out.println(users); } ② 示例
需求:查询id为1,2,3、age在20和25之间、password为1234的用户信息
SQL语句
select * from t_user where id in (1,2,3) and age between 20 and 25 and `password` = '1234'
使用Wrapper查询
@Test void testWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.in("id",1,2,3); wrapper.between("age",20,25); wrapper.eq("password","1234"); List users = userMapper.selectList(wrapper); System.out.println(users); } ③ 示例
需求:查询address中含有北,nick_name为不为空的用户信息,并且根据id倒序
SQL语句
select * from t_user where `address` like '%北%' and nick_name is not null order by id desc
使用Wrapper查询
@Test void testWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.like("address","北"); wrapper.isNotNull("nick_name"); wrapper.orderByDesc("id"); List users = userMapper.selectList(wrapper); System.out.println(users); } 5.3 QueryWrapper
使用
select
方法可以设置要查询的字段① 方法一
select(String... sqlSelect);
参数
查询的字段
@Test void testQueryWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.select("id","nick_name","address"); List users = userMapper.selectList(wrapper); System.out.println(users); } ② 方法二
select(Predicate
predicate); 参数
需要过滤的字段【无法过滤id】
@Test void testQueryWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(new User()); wrapper.select(tableFieldInfo -> "nick_name".equals(tableFieldInfo.getColumn()) || "address".equals(tableFieldInfo.getColumn())); List users = userMapper.selectList(wrapper); System.out.println(users); } ③ 方法三
select(Class
entityClass, Predicate predicate); 参数
实体类字节码
需要过滤的字段【无法过滤id】
@Test void testQueryWrapper() { QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.select(User.class,tableFieldInfo -> !"user_name".equals(tableFieldInfo.getColumn())); List users = userMapper.selectList(wrapper); System.out.println(users); } 5.4 UpdateWrapper
使用
set
方法设置只修改哪些字段,在使用的过程中还能够去构建复杂的WHERE条件@Test void testUpdateWrapper() { UpdateWrapper
wrapper = new UpdateWrapper<>(); wrapper.gt("age",18); wrapper.set("password","6666"); userMapper.update(new User(),wrapper); } 5.5 LambdaWrapper
之前在构造条件时字段名都是以字符串的形式,这种无法在预编译期确定字段名的合法性
MP提供了Lambda条件构造器,直接以实体类的方法引用形式来指定字段名
@Test void testLambdaWrapper() { LambdaQueryWrapper
wrapper = new LambdaQueryWrapper<>(); wrapper.likeRight(User::getAddress,"河"); wrapper.ge(User::getAge,"18"); wrapper.select(User::getUserName,User::getAddress); List users = userMapper.selectList(wrapper); System.out.println(users); } 六、Mapper层自定义方法
6.1 概述
虽然MP提供了很多常用的方法,但遇到一些复杂的语句时,就需要手动编写SQL语句
因为MP是在MyBatis的基础上增强,所以还是支持之前MyBatis的方式自定义方法
同时还支持在自定义方法中能够继续使用条件构造器Wrapper
6.2 Mybatis方式
① 定义接口方法
public interface UserMapper extends BaseMapper
{ User selectById(Integer id); } ② 定义xml文件
③ 编写SQL语句
id,user_name,password,nick_name,age,address 6.3 使用条件构造器
在使用自定义方法时,如果也想像MP中自定的方法一样使用条件构造器,只需要以下配置:
方法定义中将Wrapper以参数传入,并指定其参数名
public interface UserMapper extends BaseMapper
{ List selectByWrapper(@Param(Constants.WRAPPER) Wrapper wrapper); }
在SQL语句中将Wrapper中的SQL片段进行拼接
注意:不能使用
#{}
,必须使用${}
,因为该SQL片段中含有关键字,需要经过预编译,不能以占位符的形式传递七、分页查询
7.1 单表分页查询
配置分页查询拦截器
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor MybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
测试分页查询
@Test void testPage() { IPage
page = new Page<>(); // 设置每页条数 page.setSize(3); // 设置查询页数 page.setCurrent(1); page = userMapper.selectPage(page,null); System.out.println(page.getRecords()); // 获取每页数据 System.out.println(page.getTotal()); // 获取总条数 } 7.2 多表分页查询
如果在进行多表查询时,并使用到分页,就可以在Mapper接口中自定义方法,然后让方法接收Page对象
需求:查询所有的用户信息以及查询所属订单
表设计
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_order -- ---------------------------- DROP TABLE IF EXISTS `t_order`; CREATE TABLE `t_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `price` int(11) NULL DEFAULT NULL COMMENT '价格', `user_id` int(11) NULL DEFAULT NULL COMMENT '创建人id', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', `version` int(11) NULL DEFAULT 1 COMMENT '版本号', `del_flag` int(1) NULL DEFAULT 1 COMMENT '1-已删除 0-未删除', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_order -- ---------------------------- INSERT INTO `t_order` VALUES (1, 200, 1, '2022-10-19 21:28:52', '2022-10-22 21:28:54', 1, 0); INSERT INTO `t_order` VALUES (2, 100, 1, '2022-10-08 21:29:11', '2022-10-18 21:29:15', 1, 0); INSERT INTO `t_order` VALUES (3, 15, 2, '2022-09-29 21:29:39', '2022-10-15 21:29:43', 1, 0); SET FOREIGN_KEY_CHECKS = 1;
定义实体类
@Data @AllArgsConstructor @NoArgsConstructor public class Order { private Long id; private Integer price; private Integer userId; private Date createTime; private Date updateTime; private Integer version; private Integer delFlag; }
定义Mapper接口
只需要定义,无需处理,拦截器会自动处理
public interface UserMapper extends BaseMapper
{ IPage selectByPage(Page page); }
编写SQL语句:
分步查询OrderMapper接口
public interface OrderMapper{ @Select("select * from t_order where user_id = #{id}") List
selectByUserId(Integer id); }
测试
@Test void testPageMethod() { IPage
page = new Page<>(); page.setSize(2); page.setCurrent(1); page = userMapper.selectByPage(page); System.out.println(page.getRecords()); System.out.println(page.getTotal()); } 八、Service接口
8.1 概述
在实际业务中肯定需要定义Service接口,MP中提供了Service层的实现。接口继承
IService
,其实现类继承ServiceImpl
,即可使用相对于Mapper接口,Service层提供了更多批量操作的方法
8.2 使用
接口
public interface UserService extends IService
{ }
实现类
@Service public class UserServiceImpl extends ServiceImpl
implements UserService { }
测试
@Autowired UserService userService; @Test void testServiceMethod() { User user = userService.getById(3); System.out.println(user); }
其他方法查看官方文档
8.3 自定义Service层方法
接口
public interface UserService extends IService
{ User selectByIdOfOrder(Integer id); }
实现类
@Service public class UserServiceImpl extends ServiceImpl
implements UserService { @Autowired OrderMapper orderMapper; @Override public User selectByIdOfOrder(Integer id) { // 获取mapper UserMapper userMapper = baseMapper; User user = userMapper.selectById(1); List orders = orderMapper.selectByUserId(user.getId()); user.setList(orders); return user; } }
测试
@Autowired UserService userService; @Test void testCustomService() { User user = userService.selectByIdOfOrder(1); System.out.println(user); }
九、自动填充
9.1 概述
在实际业务中的表都会有更新时间、创建时间等字段
可以使用
@TableField
注解中的fill
属性来设置字段的自动填充9.2 使用
① 添加注解
使用
@TableField
注解中的fill
属性来标注哪些字段需要自动填充,加了注解MP才会在SQL语句中为我们预留字段。该属性的属性值就代表进行什么操作时进行自动填充,该属性值有:
INSERT:进行增加操作时自动填充
UPDATE:进行更新操作时自动填充
INSERT_UPDATE:进行增加和更新时自动填充
DEFAULT:默认不处理
public class Order { // ... @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.UPDATE) private Date updateTime; }
② 自定义填充处理器 MyMetaObjectHandler
@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // this.setFieldValByName("createTime",LocalDateTime.now(),metaObject); this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill(MetaObject metaObject) { // this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } }
注意:
未注释的地方,时间类型只能是
LocalDateTime
注释的地方,可以传入任意类型。比如:
Date
,LocalDateTime
如果参数中的类型和实体类中的类型不匹配,传入的值为
null
自动填充的值为
LocalDateTime.now()
,那么对应的属性类型必须为LocalDateTime
自动填充的值为
new Date()
,那么对应的属性类型必须为Date
如果
mysql-connector-java
版本低于5.1.37,使用Java8
的日期类型会抛出异常
异常信息:Data truncation: Incorrect datetime value: '\xAC\xED\x00\x05sr\x00\x0Djava.time.Ser\x95]\x84\xBA\x1B"H\xB2\x0C\x00\x00xpw\x0E\x05\x00\x00\x07\xE6\x0A\x14\x0C\x0B2$\xA8'\xC0' for column 'update_time' at row 1
十、逻辑删除
MP也支持逻辑删除的处理,只需要配置好逻辑删除的的实体类属性名,再指定删除的值和未删除的值即可
注意:如果是3.3.0之前的版本,属性类中需要加入
@TableLogic
注解mybatis-plus: global-config: db-config: logic-delete-field: delFlag # 实体类属性名 logic-delete-value: 1 # 逻辑已删除值(默认是1) logic-not-delete-value: 0 # 逻辑未删除值(默认是0)
删除
将逻辑删除的字段修改成
UPDATE t_order SET del_flag=1 WHERE id=? AND del_flag=0
查询
SELECT id,price,user_id,create_time,update_time,version,del_flag FROM t_order WHERE del_flag=0
十一、乐观锁
11.1 概述
在并发操作时,我们需要保证对数据进行操作时不会发生冲突。乐观锁就是一种解决方案,通过版本号防止操作数据发生冲突问题
使用乐观锁,一般会在表中加入一个version字段,每次对某个列进行操作,对应的version版本+1
在进行更新时操作时,先去查询对应数据的version值,然后在执行修改的时候:set version = 老版本 + 1 where version = 老版本
如果在此期间有人修改了这个版本号,那么这次的修改将会失败
手动实现乐观锁有点麻烦,所以MP为我们提供了插件进行使用
11.2 演示冲突
两个线程
同时
去更新同一条
数据@Test void testVersion() { new Thread(() -> { Order order = new Order(); order.setId(6L); order.setPrice(55); int count = orderMapper.updateById(order); System.out.println("分支线程 -->"+count); }).start(); Order order = new Order(); order.setId(6L); order.setPrice(66); int count = orderMapper.updateById(order); System.out.println("主线程 -->"+count); }
都完成了修改:最后一次修改后的数据覆盖第一次修改后的数据
==> Preparing: UPDATE t_order SET price=?,WHERE id=? ==> Preparing: UPDATE t_order SET price=?, update_time=? WHERE id=? ==> Parameters: 55(Integer), 6(Long) ==> Parameters: 66(Integer), 6(Long) <== Updates: 1 <== Updates: 1 分支线程 -->1 主线程 -->1
11.3 使用乐观锁解决
① 手动解决
@Test void testVersion() { new Thread(() -> { Order order = orderMapper.selectById(6L); UpdateWrapper
wrapper = new UpdateWrapper<>(); wrapper.set("price",333); wrapper.set("version",order.getVersion()+1); wrapper.eq("id",order.getId()); wrapper.eq("version",order.getVersion()); int count = orderMapper.update(new Order(), wrapper); System.out.println("分支线程 -->"+count); }).start(); Order order = orderMapper.selectById(6L); UpdateWrapper wrapper = new UpdateWrapper<>(); wrapper.set("price",222); wrapper.set("version",order.getVersion()+1); wrapper.eq("id",order.getId()); wrapper.eq("version",order.getVersion()); int count = orderMapper.update(new Order(), wrapper); System.out.println("主线程 -->"+count); } ==> Preparing: UPDATE t_order SET price=?,version=? WHERE (id = ? AND version = ?) ==> Preparing: UPDATE t_order SET price=?,version=? WHERE (id = ? AND version = ?) ==> Parameters: 222(Integer), 2(Integer), 6(Long), 1(Integer) ==> Parameters: 333(Integer), 2(Integer), 6(Long), 1(Integer) <== Updates: 0 分支线程 -->0 <== Updates: 1 主线程 -->1
② 借助MP
在属性上加上
@Version
注解public class Order { // ... @Version private Integer version; }
配置对应的插件
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor versionMybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
测试
@Test void testVersion() { new Thread(() -> { Order order = orderMapper.selectById(6L); order.setPrice(1234); int count = orderMapper.updateById(order); System.out.println("分支线程 -->"+count); }).start(); Order order = orderMapper.selectById(6L); order.setPrice(6789); int count = orderMapper.updateById(order); System.out.println("主线程 -->"+count); }
==> Preparing: UPDATE t_order SET price=?, version=? WHERE id=? AND version=? ==> Preparing: UPDATE t_order SET price=?, version=? WHERE id=? AND version=? ==> Parameters: 1234(Integer), 2(Integer), 6(Long), 1(Integer) ==> Parameters: 6789(Integer), 2(Integer), 6(Long), 1(Integer) <== Updates: 0 <== Updates: 1
11.4 多插件问题
在MP3.4.0版本以后,如果需要配置多个插件的时候要注意:
只需要注入一个
MybatisPlusInterceptor
对象,然后将插件对象进行添加需要注意顺序关系,建议使用一下顺序:
多租户,动态表名
分页,乐观锁
sql 性能规范,防止全表更新与删除
例如:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor MybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件 return interceptor; } }
十二、代码生成器
MP提供的代码生成器按照要求能够自动生成Service层、Controller层、实体类、Mapper层。
com.baomidou mybatis-plus-generator 3.5.1 org.freemarker freemarker public class MybatisPlusGenerate { // 项目全路径 public static final String FILE_URL = System.getProperty("user.dir"); public static final String URL = "jdbc:mysql://localhost:3306/jiuxiao"; public static final String USER_NAME = "root"; public static final String PASSWORD = "1234"; public static void main(String[] args) { FastAutoGenerator.create(URL,USER_NAME,PASSWORD) .globalConfig(builder -> { builder.author("酒萧") // 设置作者 .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir(FILE_URL+"\\order-service\\src\\main\\java"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.jiuxiao") // 设置父包名 //.moduleName("mybatisplus") // 设置父包模块名 //.entity("pojo") // 设置实体类包名 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, FILE_URL+"\\order-service\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("t_order")// 设置需要生成的表名 .addTablePrefix("t_", "c_") // 设置过滤表前缀 .entityBuilder().enableLombok() // 开启lombok .enableTableFieldAnnotation() // 开启@tableField .controllerBuilder().enableRestStyle() // 开启@RestController .serviceBuilder().formatServiceFileName("%sService") // 设置接口名称 .formatServiceImplFileName("%sServiceImpl").build(); // 设置接口实现类名称 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }