SpringBoot整合MyBatis-Plus3.1教程详解
一.说明
Mybatis-Plus是一个Mybatis框架的增强插件,根据官方描述,MP只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑.并且只需简单配置,即可快速进行CRUD操作,从而节省大量时间.代码生成,分页,性能分析等功能一应俱全,最新已经更新到了3.1.1版本了,3.X系列支持lambda语法,让我在写条件构造的时候少了很多的"魔法值",从代码结构上更简洁了.
二.项目环境
- MyBatis-Plus版本:3.1.0
- SpringBoot版本:2.1.5
- JDK版本:1.8
Maven依赖如下:
org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test com.baomidou mybatis-plus-boot-starter 3.1.0 com.alibaba druid 1.1.6
配置如下:
#配置端口 server: port:8081 spring: #配置数据源 datasource: driver-class-name:com.mysql.cj.jdbc.Driver url:jdbc:mysql://localhost:3306/mp_student?useUnicode=true&characterEncoding=utf-8 username:root password:root type:com.alibaba.druid.pool.DruidDataSource #mybatis-plus相关配置 mybatis-plus: #xml扫描,多个目录用逗号或者分号分隔(告诉Mapper所对应的XML文件位置) mapper-locations:classpath:mapper/*.xml #以下配置均有默认值,可以不设置 global-config: db-config: #主键类型AUTO:"数据库ID自增"INPUT:"用户输入ID",ID_WORKER:"全局唯一ID(数字类型唯一ID)",UUID:"全局唯一IDUUID"; id-type:auto #字段策略IGNORED:"忽略判断"NOT_NULL:"非NULL判断")NOT_EMPTY:"非空判断" field-strategy:NOT_EMPTY #数据库类型 db-type:MYSQL configuration: #是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射 map-underscore-to-camel-case:true #如果查询结果中包含空值的列,则MyBatis在映射的时候,不会映射这个字段 call-setters-on-nulls:true #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 log-impl:org.apache.ibatis.logging.stdout.StdOutImpl 表结构: CREATETABLE`user_info`( `id`bigint(11)NOTNULLAUTO_INCREMENTCOMMENT'ID', `name`varchar(32)DEFAULTNULLCOMMENT'姓名', `age`int(11)DEFAULTNULLCOMMENT'年龄', `skill`varchar(32)DEFAULTNULLCOMMENT'技能', `evaluate`varchar(64)DEFAULTNULLCOMMENT'评价', `fraction`bigint(11)DEFAULTNULLCOMMENT'分数', PRIMARYKEY(`id`) )ENGINE=InnoDBAUTO_INCREMENT=16DEFAULTCHARSET=utf8mb4COMMENT='学生信息表'; 表数据: INSERTINTO`user_info`VALUES(1,'小明',20,'画画','该学生在画画方面有一定天赋',89); INSERTINTO`user_info`VALUES(2,'小兰',19,'游戏','近期该学生由于游戏的原因导致分数降低了',64); INSERTINTO`user_info`VALUES(3,'张张',18,'英语','近期该学生参加英语比赛获得二等奖',90); INSERTINTO`user_info`VALUES(4,'大黄',20,'体育','该学生近期由于参加篮球比赛,导致脚伤',76); INSERTINTO`user_info`VALUES(5,'大白',17,'绘画','该学生参加美术大赛获得三等奖',77); INSERTINTO`user_info`VALUES(7,'小龙',18,'JAVA','该学生是一个在改BUG的码农',59); INSERTINTO`user_info`VALUES(9,'Sans',18,'睡觉','Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子',60); INSERTINTO`user_info`VALUES(10,'papyrus',18,'JAVA','Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子',58); INSERTINTO`user_info`VALUES(11,'删除数据1',3,'画肖像',NULL,61); INSERTINTO`user_info`VALUES(12,'删除数据2',3,NULL,NULL,61); INSERTINTO`user_info`VALUES(13,'删除数据3',3,NULL,NULL,61); INSERTINTO`user_info`VALUES(14,'删除数据4',5,'删除',NULL,10); INSERTINTO`user_info`VALUES(15,'删除数据5',6,'删除',NULL,10);
三.编写基础类
在启动类上添加扫描DAO的注解
@SpringBootApplication
@MapperScan(basePackages={"com.mp.demo.dao"})//扫描DAO
publicclassDemoApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(DemoApplication.class,args);
}
}
编写Config配置类
/**
*@DescriptionMybatisPlus配置类
*@AuthorSans
*@CreateTime2019/5/2617:20
*/
@Configuration
publicclassMybatisPlusConfig{
/**
*mybatis-plusSQL执行效率插件【生产环境可以关闭】
*/
@Bean
publicPerformanceInterceptorperformanceInterceptor(){
returnnewPerformanceInterceptor();
}
/**
*分页插件
*/
@Bean
publicPaginationInterceptorpaginationInterceptor(){
returnnewPaginationInterceptor();
}
}
编写Entity类
/**
*@Description学生信息实体类
*@AuthorSans
*@CreateTime2019/5/2621:41
*/
@Data
@TableName("user_info")//@TableName中的值对应着表名
publicclassUserInfoEntity{
/**
*主键
*@TableId中可以决定主键的类型,不写会采取默认值,默认值可以在yml中配置
*AUTO:数据库ID自增
*INPUT:用户输入ID
*ID_WORKER:全局唯一ID,Long类型的主键
*ID_WORKER_STR:字符串全局唯一ID
*UUID:全局唯一ID,UUID类型的主键
*NONE:该类型为未设置主键类型
*/
@TableId(type=IdType.AUTO)
privateLongid;
/**
*姓名
*/
privateStringname;
/**
*年龄
*/
privateIntegerage;
/**
*技能
*/
privateStringskill;
/**
*评价
*/
privateStringevaluate;
/**
*分数
*/
privateLongfraction;
}
编写Dao类
/** *@Description用户信息DAO *@AuthorSans *@CreateTime2019/6/816:24 */ publicinterfaceUserInfoDaoextendsBaseMapper{ }
编写Service类
/** *@Description用户业务接口 *@AuthorSans *@CreateTime2019/6/816:26 */ publicinterfaceUserInfoServiceextendsIService{ }
编写ServiceImpl类
/** *@Description用户业务实现 *@AuthorSans *@CreateTime2019/6/816:26 */ @Service @Transactional publicclassUserInfoSerivceImplextendsServiceImplimplementsUserInfoService{ }
四.MyBatis-Plus基础演示
这里我们看到,service中我们没有写任何方法,MyBatis-Plus官方封装了许多基本CRUD的方法,可以直接使用大量节约时间,MP共通方法详见IService,ServiceImpl,BaseMapper源码,写入操作在ServiceImpl中已有事务绑定,这里我们举一些常用的方法演示.
/**
*@DescriptionUserInfoController
*@AuthorSans
*@CreateTime2019/6/816:27
*/
@RestController
@RequestMapping("/userInfo")
publicclassUserInfoController{
@Autowired
privateUserInfoServiceuserInfoService;
/**
*根据ID获取用户信息
*@AuthorSans
*@CreateTime2019/6/816:34
*@ParamuserId用户ID
*@ReturnUserInfoEntity用户实体
*/
@RequestMapping("/getInfo")
publicUserInfoEntitygetInfo(StringuserId){
UserInfoEntityuserInfoEntity=userInfoService.getById(userId);
returnuserInfoEntity;
}
/**
*查询全部信息
*@AuthorSans
*@CreateTime2019/6/816:35
*@ParamuserId用户ID
*@ReturnList用户实体集合
*/
@RequestMapping("/getList")
publicListgetList(){
ListuserInfoEntityList=userInfoService.list();
returnuserInfoEntityList;
}
/**
*分页查询全部数据
*@AuthorSans
*@CreateTime2019/6/816:37
*@ReturnIPage分页数据
*/
@RequestMapping("/getInfoListPage")
publicIPagegetInfoListPage(){
//需要在Config配置类中配置分页插件
IPagepage=newPage<>();
page.setCurrent(5);//当前页
page.setSize(1);//每页条数
page=userInfoService.page(page);
returnpage;
}
/**
*根据指定字段查询用户信息集合
*@AuthorSans
*@CreateTime2019/6/816:39
*@ReturnCollection用户实体集合
*/
@RequestMapping("/getListMap")
publicCollectiongetListMap(){
Mapmap=newHashMap<>();
//kay是字段名value是字段值
map.put("age",20);
CollectionuserInfoEntityList=userInfoService.listByMap(map);
returnuserInfoEntityList;
}
/**
*新增用户信息
*@AuthorSans
*@CreateTime2019/6/816:40
*/
@RequestMapping("/saveInfo")
publicvoidsaveInfo(){
UserInfoEntityuserInfoEntity=newUserInfoEntity();
userInfoEntity.setName("小龙");
userInfoEntity.setSkill("JAVA");
userInfoEntity.setAge(18);
userInfoEntity.setFraction(59L);
userInfoEntity.setEvaluate("该学生是一个在改BUG的码农");
userInfoService.save(userInfoEntity);
}
/**
*批量新增用户信息
*@AuthorSans
*@CreateTime2019/6/816:42
*/
@RequestMapping("/saveInfoList")
publicvoidsaveInfoList(){
//创建对象
UserInfoEntitysans=newUserInfoEntity();
sans.setName("Sans");
sans.setSkill("睡觉");
sans.setAge(18);
sans.setFraction(60L);
sans.setEvaluate("Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子");
UserInfoEntitypapyrus=newUserInfoEntity();
papyrus.setName("papyrus");
papyrus.setSkill("JAVA");
papyrus.setAge(18);
papyrus.setFraction(58L);
papyrus.setEvaluate("Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子");
//批量保存
Listlist=newArrayList<>();
list.add(sans);
list.add(papyrus);
userInfoService.saveBatch(list);
}
/**
*更新用户信息
*@AuthorSans
*@CreateTime2019/6/816:47
*/
@RequestMapping("/updateInfo")
publicvoidupdateInfo(){
//根据实体中的ID去更新,其他字段如果值为null则不会更新该字段,参考yml配置文件
UserInfoEntityuserInfoEntity=newUserInfoEntity();
userInfoEntity.setId(1L);
userInfoEntity.setAge(19);
userInfoService.updateById(userInfoEntity);
}
/**
*新增或者更新用户信息
*@AuthorSans
*@CreateTime2019/6/816:50
*/
@RequestMapping("/saveOrUpdateInfo")
publicvoidsaveOrUpdate(){
//传入的实体类userInfoEntity中ID为null就会新增(ID自增)
//实体类ID值存在,如果数据库存在ID就会更新,如果不存在就会新增
UserInfoEntityuserInfoEntity=newUserInfoEntity();
userInfoEntity.setId(1L);
userInfoEntity.setAge(20);
userInfoService.saveOrUpdate(userInfoEntity);
}
/**
*根据ID删除用户信息
*@AuthorSans
*@CreateTime2019/6/816:52
*/
@RequestMapping("/deleteInfo")
publicvoiddeleteInfo(StringuserId){
userInfoService.removeById(userId);
}
/**
*根据ID批量删除用户信息
*@AuthorSans
*@CreateTime2019/6/816:55
*/
@RequestMapping("/deleteInfoList")
publicvoiddeleteInfoList(){
ListuserIdlist=newArrayList<>();
userIdlist.add("12");
userIdlist.add("13");
userInfoService.removeByIds(userIdlist);
}
/**
*根据指定字段删除用户信息
*@AuthorSans
*@CreateTime2019/6/816:57
*/
@RequestMapping("/deleteInfoMap")
publicvoiddeleteInfoMap(){
//kay是字段名value是字段值
Mapmap=newHashMap<>();
map.put("skill","删除");
map.put("fraction",10L);
userInfoService.removeByMap(map);
}
}
五.MyBatis-Plus的QueryWrapper条件构造器
当查询条件复杂的时候,我们可以使用MP的条件构造器,请参考下面的QueryWrapper条件参数说明
下面我们来举一些常见的示例
/**
*@DescriptionUserInfoPlusController
*@AuthorSans
*@CreateTime2019/6/914:52
*/
@RestController
@RequestMapping("/userInfoPlus")
publicclassUserInfoPlusController{
@Autowired
privateUserInfoServiceuserInfoService;
/**
*MP扩展演示
*@AuthorSans
*@CreateTime2019/6/816:37
*@ReturnMap返回数据
*/
@RequestMapping("/getInfoListPlus")
publicMapgetInfoListPage(){
//初始化返回类
Mapresult=newHashMap<>();
//查询年龄等于18岁的学生
//等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREage=18
QueryWrapperqueryWrapper1=newQueryWrapper<>();
queryWrapper1.lambda().eq(UserInfoEntity::getAge,18);
ListuserInfoEntityList1=userInfoService.list(queryWrapper1);
result.put("studentAge18",userInfoEntityList1);
//查询年龄大于5岁的学生且小于等于18岁的学生
//等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREage>5ANDage<=18
QueryWrapperqueryWrapper2=newQueryWrapper<>();
queryWrapper2.lambda().gt(UserInfoEntity::getAge,5);
queryWrapper2.lambda().le(UserInfoEntity::getAge,18);
ListuserInfoEntityList2=userInfoService.list(queryWrapper2);
result.put("studentAge5",userInfoEntityList2);
//模糊查询技能字段带有"画"的数据,并按照年龄降序
//等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREskillLIKE'%画%'ORDERBYageDESC
QueryWrapperqueryWrapper3=newQueryWrapper<>();
queryWrapper3.lambda().like(UserInfoEntity::getSkill,"画");
queryWrapper3.lambda().orderByDesc(UserInfoEntity::getAge);
ListuserInfoEntityList3=userInfoService.list(queryWrapper3);
result.put("studentAgeSkill",userInfoEntityList3);
//模糊查询名字带有"小"或者年龄大于18的学生
//等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREnameLIKE'%小%'ORage>18
QueryWrapperqueryWrapper4=newQueryWrapper<>();
queryWrapper4.lambda().like(UserInfoEntity::getName,"小");
queryWrapper4.lambda().or().gt(UserInfoEntity::getAge,18);
ListuserInfoEntityList4=userInfoService.list(queryWrapper4);
result.put("studentOr",userInfoEntityList4);
//查询评价不为null的学生,并且分页
//等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREevaluateISNOTNULLLIMIT0,5
IPagepage=newPage<>();
page.setCurrent(1);
page.setSize(5);
QueryWrapperqueryWrapper5=newQueryWrapper<>();
queryWrapper5.lambda().isNotNull(UserInfoEntity::getEvaluate);
page=userInfoService.page(page,queryWrapper5);
result.put("studentPage",page);
returnresult;
}
}
六.自定义SQL
引入Mybatis-Plus不会对项目现有的Mybatis构架产生任何影响,而且Mybatis-Plus支持所有Mybatis原生的特性,这也是我喜欢使用它的原因之一,由于某些业务复杂,我们可能要自己去写一些比较复杂的SQL语句,我们举一个简单的例子来演示自定义SQL.
示例:查询大于设置分数的学生(分数为动态输入,且有分页)
编写Mapper.xml文件
SELECT*FROMuser_infoWHEREfraction>#{fraction}
在DAO中加入方法
/** *查询大于该分数的学生 *@AuthorSans *@CreateTime2019/6/914:28 *@Parampage分页参数 *@Paramfraction分数 *@ReturnIPage分页数据 */ IPage selectUserInfoByGtFraction(IPage page,Longfraction);
在service加入方法
/** *查询大于该分数的学生 *@AuthorSans *@CreateTime2019/6/914:27 *@Parampage分页参数 *@Paramfraction分数 *@ReturnIPage分页数据 */ IPage selectUserInfoByGtFraction(IPage page,Longfraction);
在serviceImpl加入方法
/** *查询大于该分数的学生 *@AuthorSans *@CreateTime2019/6/914:27 *@Parampage分页参数 *@Paramfraction分数 *@ReturnIPage分页数据 */ @Override publicIPage selectUserInfoByGtFraction(IPage page,Longfraction){ returnthis.baseMapper.selectUserInfoByGtFraction(page,fraction); }
在Controller中测试
/** *MP自定义SQL *@AuthorSans *@CreateTime2019/6/914:37 *@ReturnIPage分页数据 */ @RequestMapping("/getInfoListSQL") publicIPage getInfoListSQL(){ //查询大于60分以上的学生,并且分页 IPage page=newPage<>(); page.setCurrent(1); page.setSize(5); page=userInfoService.selectUserInfoByGtFraction(page,60L); returnpage; }
七.项目源码
项目源码:
https://gitee.com/liselotte/spring-boot-mp-demo
个人确实很喜欢用MyBatis-Plus,不仅节约时间,代码也简洁干净,它给了我那时候从SSM到SpringBoot过度的那种感觉
嗯,这玩意真香~