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") publicList getList(){ List userInfoEntityList=userInfoService.list(); returnuserInfoEntityList; } /** *分页查询全部数据 *@AuthorSans *@CreateTime2019/6/816:37 *@ReturnIPage 分页数据 */ @RequestMapping("/getInfoListPage") publicIPage getInfoListPage(){ //需要在Config配置类中配置分页插件 IPage page=newPage<>(); page.setCurrent(5);//当前页 page.setSize(1);//每页条数 page=userInfoService.page(page); returnpage; } /** *根据指定字段查询用户信息集合 *@AuthorSans *@CreateTime2019/6/816:39 *@ReturnCollection 用户实体集合 */ @RequestMapping("/getListMap") publicCollection getListMap(){ Map map=newHashMap<>(); //kay是字段名value是字段值 map.put("age",20); Collection userInfoEntityList=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是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子"); //批量保存 List list=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(){ List userIdlist=newArrayList<>(); userIdlist.add("12"); userIdlist.add("13"); userInfoService.removeByIds(userIdlist); } /** *根据指定字段删除用户信息 *@AuthorSans *@CreateTime2019/6/816:57 */ @RequestMapping("/deleteInfoMap") publicvoiddeleteInfoMap(){ //kay是字段名value是字段值 Map map=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") publicMap getInfoListPage(){ //初始化返回类 Map result=newHashMap<>(); //查询年龄等于18岁的学生 //等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREage=18 QueryWrapper queryWrapper1=newQueryWrapper<>(); queryWrapper1.lambda().eq(UserInfoEntity::getAge,18); List userInfoEntityList1=userInfoService.list(queryWrapper1); result.put("studentAge18",userInfoEntityList1); //查询年龄大于5岁的学生且小于等于18岁的学生 //等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREage>5ANDage<=18 QueryWrapper queryWrapper2=newQueryWrapper<>(); queryWrapper2.lambda().gt(UserInfoEntity::getAge,5); queryWrapper2.lambda().le(UserInfoEntity::getAge,18); List userInfoEntityList2=userInfoService.list(queryWrapper2); result.put("studentAge5",userInfoEntityList2); //模糊查询技能字段带有"画"的数据,并按照年龄降序 //等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREskillLIKE'%画%'ORDERBYageDESC QueryWrapper queryWrapper3=newQueryWrapper<>(); queryWrapper3.lambda().like(UserInfoEntity::getSkill,"画"); queryWrapper3.lambda().orderByDesc(UserInfoEntity::getAge); List userInfoEntityList3=userInfoService.list(queryWrapper3); result.put("studentAgeSkill",userInfoEntityList3); //模糊查询名字带有"小"或者年龄大于18的学生 //等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREnameLIKE'%小%'ORage>18 QueryWrapper queryWrapper4=newQueryWrapper<>(); queryWrapper4.lambda().like(UserInfoEntity::getName,"小"); queryWrapper4.lambda().or().gt(UserInfoEntity::getAge,18); List userInfoEntityList4=userInfoService.list(queryWrapper4); result.put("studentOr",userInfoEntityList4); //查询评价不为null的学生,并且分页 //等价SQL:SELECTid,name,age,skill,evaluate,fractionFROMuser_infoWHEREevaluateISNOTNULLLIMIT0,5 IPage page=newPage<>(); page.setCurrent(1); page.setSize(5); QueryWrapper queryWrapper5=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过度的那种感觉
嗯,这玩意真香~