MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
具体可以参考MyBatis-Plus官网:MyBatis-Plus官网
目录
- SpringBoot集成Mybatis-Plus框架
- 环境
- 数据库表
- Java实体类 UserInfo
- application.yml 主配置
- 编写mapper
- 主启动类
- Mapper CRUD操作
- 新增
- 查询
- 分页查询
- 分页插件配置
- 分页查询 测试结果
- 删除
- 更新
- Service CRUD操作
环境
- Java1.8
- maven
- spring boot 2.2.4.RELEASE
- mybatis-plus-boot-starte 3.3.2
- mysql
maven xml 配置文件
org.springframework.boot spring-boot-starter-parent 2.2.4.RELEASE com.baomidou mybatis-plus-boot-starter 3.3.2 mysql mysql-connector-java
数据库表
用户基本信息表
-- 建表语句 CREATE TABLE `user_info` ( `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID主键', `user_name` varchar(100) NOT NULL COMMENT '用户姓名', `user_idcard` varchar(20) DEFAULT NULL COMMENT '身份证', `age` int(5) DEFAULT NULL COMMENT '年龄', `home_address` varchar(500) DEFAULT NULL COMMENT '家庭地址', `height` int(5) DEFAULT NULL COMMENT '身高', `birth_day` date DEFAULT NULL COMMENT '出生日期', `sex` varchar(5) DEFAULT NULL COMMENT '性别', PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Java实体类 UserInfo
@Data
@Builder
@TableName("user_info")
public class UserInfo {
// 用户ID
// @TableId 标注为表主键ID,若是没有标注,则 updateById会报错
@TableId
private long userId ;
// 用户姓名
@TableField
private String userName ;
// 用户身份证
private String userIdcard ;
// 家庭地址
private String homeAddress ;
// 年龄
private int age ;
// 身高CM
private int height ;
// 性别
private String sex ;
// 出生日期
// JSON 输出格式化
@JSONField(format = "yyyy年MM月dd日")
private Date birthDay ;
}
注意:@TableId 标注为表主键ID,若是没有标注,则 updateById会报错,具体报错,参考下面的:CRUD操作/更新
其他字段若是跟数据库保持一致或者数据库是以下划线分割,Java类属性是以驼峰命名的,则可以不用添加 @TableField,mybatis-plus框架会自动匹配
数据库字段值, 不需要配置该值的情况:
当 com.baomidou.mybatisplus.core.MybatisConfiguration.mapUnderscoreToCamelCase 为 true 时, (mp下默认是true,mybatis默认是false), 数据库字段值.replace("_","").toUpperCase() == 实体属性名.toUpperCase()
当 com.baomidou.mybatisplus.core.MybatisConfiguration.mapUnderscoreToCamelCase 为 false 时, 数据库字段值.toUpperCase() == 实体属性名.toUpperCase()
若是JavaBean中某些属性不是数据库表字段的,则可以添加 @TableField(exist = false) 来避免自动生成的SQL字段不存在问题
application.yml 主配置
配置数据源
server:
port: 8080
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: mysql
编写mapper
集成mybatis-plus mapper接口继承 baseMapper 即可,然后对单表的CRUD的操作就可以不用编写xml文件了,类似JPA框架,非常方便
@Repository public interface IUserInfoMapper extends baseMapper{ }
baseMapper 对单表的常用方法:
主启动类
@SpringBootApplication
@MapperScan("com.tianya.springboot.mybatis.plus.mapper")
public class LearnMybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(LearnMybatisPlusApplication.class, args);
}
}
Mapper CRUD操作
mapper接口 继承 baseMapper 接口,就可以实现对单表的 CRUD快捷API操作
来实际测试一下 mybatis-plus便捷之处
此处使用了一个自动随机生成测试数据的工具jar
com.github.javafaker javafaker 1.0.2
这个工具可以随机生成测试数据,避免自己制造测试数据头痛
新增
// 插入对象 int insert(T entity);
测试新增用户基本信息:
@Test
public void insert() {
Faker faker = new Faker(Locale.SIMPLIFIED_CHINESE);
// 测试 新增 10 个用户
for (int i = 0; i < 10; i++) {
// 用户信息
UserInfo userInfo = UserInfo.builder()
.userName(faker.name().fullName())
.userIdcard(faker.idNumber().invalid())
.homeAddress(faker.address().fullAddress())
.birthDay(faker.date().birthday())
.age(faker.number().numberBetween(1, 120))
.height(faker.number().numberBetween(50, 200))
.sex(SEX_MAP.get(faker.number().numberBetween(0, 2)))
.build();
// 新增
userInfoMapper.insert(userInfo);
}
}
结果如下:
[
{
"age":75,
"birthDay":"1974年10月28日",
"height":94,
"homeAddress":"余巷",
"sex":"女",
"userId":11,
"userIdcard":"000-98-3709",
"userName":"林烨霖"
},
{
"age":87,
"birthDay":"1977年09月05日",
"height":118,
"homeAddress":"Suite 078 袁桥36104号, 金华, 浙 723135",
"sex":"女",
"userId":27,
"userIdcard":"114-00-3888",
"userName":"邹雨泽"
},
{
"age":12,
"birthDay":"1965年09月05日",
"height":150,
"homeAddress":"Suite 118 谢中心0798号, 衢州, 桂 350938",
"sex":"男",
"userId":28,
"userIdcard":"435-25-0000",
"userName":"范金鑫"
},
{
"age":30,
"birthDay":"1996年07月04日",
"height":84,
"homeAddress":"阎中心50号, 海口, 湘 888025",
"sex":"女",
"userId":29,
"userIdcard":"162-11-0000",
"userName":"程炫明"
},
{
"age":84,
"birthDay":"1972年06月14日",
"height":144,
"homeAddress":"刘街3928号, 平顶山, 豫 904305",
"sex":"男",
"userId":30,
"userIdcard":"638-77-0000",
"userName":"汪鑫鹏"
}
]
查询
// 根据 entity 条件,查询全部记录 封装 实体对象 ListselectList( Wrapper queryWrapper); // 根据 Wrapper 条件,查询全部记录 List
查询所有
@Test
public void getList() {
// 查询所有
List selectList = userInfoMapper.selectList(null);
System.out.println("所有的用户基本信息:");
System.out.println(JSON.toJSONString(selectList, true));
}
分页查询
分页查询 mapper中 对应的 API 操作是:
// 根据 entity 条件,查询全部记录(并翻页)> E selectPage(E page, Wrapper queryWrapper); // 根据 Wrapper 条件,查询全部记录(并翻页) >> E selectMapsPage(E page, Wrapper queryWrapper);
但是此 API操作,需要搭配 mybatis-plus中的分页插件才有效果,否则查询的 全部,没有分页限制
分页插件配置
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
配置完分页插件后,可以使用mybatis-plus提供的分页API进行分页查询,也可以自定义XML文件编写查询语句
分页查询 测试结果
@Test
public void getQueryList() {
// 查询条件(查询身高在1米-2米之间的 以年龄倒序排序,查询第一页3个 TOP3)
LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(UserInfo.class)
.orderByDesc(UserInfo::getAge)
.between(UserInfo::getHeight, 100, 200);
Page page = new Page(1, 3);
page.setSearchCount(true);
// 若是没有配置 分页插件,则 selectPage 分页API 不生效
page = userInfoMapper.selectPage(page, queryWrapper);
System.out.println("分页查询:");
System.out.println("总记录数:" + page.getTotal());
System.out.println(JSON.toJSONString(page, true));
}
结果如下:
{
"current":1,
"hitCount":false,
"optimizeCountSql":true,
"orders":[],
"pages":5,
"records":[
{
"age":93,
"birthDay":"1970年07月23日",
"height":157,
"homeAddress":"段路7号, 北京, 宁 451930",
"sex":"男",
"userId":25,
"userIdcard":"666-37-8505",
"userName":"朱鹤轩"
},
{
"age":84,
"birthDay":"1972年06月14日",
"height":144,
"homeAddress":"刘街3928号, 平顶山, 豫 904305",
"sex":"男",
"userId":30,
"userIdcard":"638-77-0000",
"userName":"汪鑫鹏"
},
{
"age":79,
"birthDay":"1984年01月17日",
"height":113,
"homeAddress":"赵街",
"sex":"男",
"userId":14,
"userIdcard":"666-95-6869",
"userName":"阎俊驰"
}
],
"searchCount":true,
"size":3,
"total":14
}
删除
// 根据ID删除 int deleteById(Serializable id); // 根据 columnMap 条件,删除记录 int deleteByMap(MapcolumnMap); // 根据 entity 条件,删除记录 int delete(Wrapper wrapper); // 删除(根据ID 批量删除) int deleteBatchIds(Collection extends Serializable> idList);
根据ID删除
@Test
public void delete() {
// 删除
userInfoMapper.deleteById(20);
}
更新
// 根据 ID 修改 int updateById(@Param(Constants.ENTITY) T entity); // 根据 whereEntity 条件,更新记录 int update( T entity, WrapperupdateWrapper);
更加ID进行修改
@Test
public void update() {
// 查询单个
UserInfo userInfo = userInfoMapper.selectOne(Wrappers.lambdaQuery(UserInfo.class)
.eq(UserInfo::getUserId, 27));
System.out.println("修改前:");
System.out.println(JSON.toJSONString(userInfo, true));
// 修改值
userInfo.setAge(70);
userInfo.setSex(SEX_MAP.get(1));
userInfo.setHeight(178);
// 更新
userInfoMapper.updateById(userInfo);
System.out.println("修改后:");
System.out.println(JSON.toJSONString(userInfo, true));
}
若是出现以下错误,则说明 实体类没有添加 表ID主键注解:@TableId
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'null' in 'class com.tianya.springboot.mybatis.plus.entity.UserInfo' at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440) at com.sun.proxy.$Proxy83.update(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:287) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:65) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:96) at com.sun.proxy.$Proxy104.updateById(Unknown Source) ... 82 more
结果:
## 修改前:
{
"age":67,
"birthDay":"1977年09月05日",
"height":118,
"homeAddress":"Suite 078 袁桥36104号, 金华, 浙 723135",
"sex":"女",
"userId":27,
"userIdcard":"114-00-3888",
"userName":"邹雨泽"
}
## 修改后:
{
"age":70,
"birthDay":"1977年09月05日",
"height":178,
"homeAddress":"Suite 078 袁桥36104号, 金华, 浙 723135",
"sex":"男",
"userId":27,
"userIdcard":"114-00-3888",
"userName":"邹雨泽"
}
Service CRUD操作
mybatis-plus框架 提供了 针对 服务层service的一个基类接口,提供更加丰富的 CRUD API 操作
com.baomidou.mybatisplus.extension.service.IService
只需要 实现 IService 即可
提供的一系列操作API:
int DEFAULT_BATCH_SIZE = 1000;
default boolean save(T entity) {
return SqlHelper.retBool(getbaseMapper().insert(entity));
}
@Transactional(rollbackFor = Exception.class)
default boolean saveBatch(Collection entityList) {
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
}
boolean saveBatch(Collection entityList, int batchSize);
@Transactional(rollbackFor = Exception.class)
default boolean saveOrUpdateBatch(Collection entityList) {
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
}
boolean saveOrUpdateBatch(Collection entityList, int batchSize);
default boolean removeById(Serializable id) {
return SqlHelper.retBool(getbaseMapper().deleteById(id));
}
default boolean removeByMap(Map columnMap) {
Assert.notEmpty(columnMap, "error: columnMap must not be empty");
return SqlHelper.retBool(getbaseMapper().deleteByMap(columnMap));
}
default boolean remove(Wrapper queryWrapper) {
return SqlHelper.retBool(getbaseMapper().delete(queryWrapper));
}
default boolean removeByIds(Collection extends Serializable> idList) {
if (CollectionUtils.isEmpty(idList)) {
return false;
}
return SqlHelper.retBool(getbaseMapper().deleteBatchIds(idList));
}
default boolean updateById(T entity) {
return SqlHelper.retBool(getbaseMapper().updateById(entity));
}
default boolean update(Wrapper updateWrapper) {
return update(null, updateWrapper);
}
default boolean update(T entity, Wrapper updateWrapper) {
return SqlHelper.retBool(getbaseMapper().update(entity, updateWrapper));
}
@Transactional(rollbackFor = Exception.class)
default boolean updateBatchById(Collection entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
boolean updateBatchById(Collection entityList, int batchSize);
boolean saveOrUpdate(T entity);
default T getById(Serializable id) {
return getbaseMapper().selectById(id);
}
default List listByIds(Collection extends Serializable> idList) {
return getbaseMapper().selectBatchIds(idList);
}
default List listByMap(Map columnMap) {
return getbaseMapper().selectByMap(columnMap);
}
default T getOne(Wrapper queryWrapper) {
return getOne(queryWrapper, true);
}
T getOne(Wrapper queryWrapper, boolean throwEx);
Map getMap(Wrapper queryWrapper);
V getObj(Wrapper queryWrapper, Function super Object, V> mapper);
default int count() {
return count(Wrappers.emptyWrapper());
}
default int count(Wrapper queryWrapper) {
return SqlHelper.retCount(getbaseMapper().selectCount(queryWrapper));
}
default List list(Wrapper queryWrapper) {
return getbaseMapper().selectList(queryWrapper);
}
default List list() {
return list(Wrappers.emptyWrapper());
}
default > E page(E page, Wrapper queryWrapper) {
return getbaseMapper().selectPage(page, queryWrapper);
}
default > E page(E page) {
return page(page, Wrappers.emptyWrapper());
}
default List



