一。MP里面的增删改查 在当前盛行的SpringBoot项目中,整合持久层这一块,目前主流的有两种:JPA和MyBatisPlus。至于哪个用得更多一些,这个主要还是看每个公司的技术架构,但硬是要说一个最为常用的,我认为是MyBatisPlus,而在这里也是对MyBatisPlus的一个使用进行演示 好了,废话不多说,直接开始吧。为了减少冗余,下面所有MyBatisPlus都使用MP来代替1。1项目搭建 项目的创建就直接跳过了,直接从依赖开始吧。开始之前得先弄个表,表怎么弄都行,下面这个是我测试建的,可以参考一下DROPTABLEIFEXISTSCREATETABLEuser(idint(0)NOTNULLAUTOINCREMENTCOMMENTid,namevarchar(11)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciNOTNULLCOMMENT用户名,ageint(0)NOTNULLCOMMENT年龄,mobilevarchar(11)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciNULLDEFAULTNULLCOMMENT手机号,emailvarchar(55)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciNULLDEFAULTNULLCOMMENT邮箱,createtimedatetime(0)NULLDEFAULTNULLCOMMENT创建时间,createbyvarchar(255)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciNULLDEFAULTNULLCOMMENT创建人,updatetimedatetime(0)NULLDEFAULTNULLCOMMENT更改时间,updatebyvarchar(255)CHARACTERSETutf8mb4COLLATEutf8mb40900aiciNULLDEFAULTNULLCOMMENT更改人,isdeleteint(0)NULLDEFAULTNULLCOMMENT是否删除0未删除1已删除,PRIMARYKEY(id)USINGBTREE)ENGINEInnoDBAUTOINCREMENT3554031CHARACTERSETutf8mb4COLLATEutf8mb40900aiciCOMMENT用户表ROWFORMATD依赖(1)目前MP的最新版本!Mybatisplus依赖dependencygroupIdcom。baomidougroupIdmybatisplusbootstarterartifactIdversion3。5。2versiondependency (2)当然,如果你想使用MP中的快速生成实体类,需要添加MP中的一个工具依赖且需导入一个模板引擎的依赖(模板可以自定义,具体看MP官网的例子,这里直接使用Freemark)!Mybatisplus逆向自动生成实体类所需依赖dependencygroupIdcom。baomidougroupIdmybatisplusgeneratorartifactIdversion3。5。2versiondependencydependencygroupIdorg。freemarkergroupIdfreemarkerartifactIdversion2。3。31versiondependency(3)以上的都是MP中所需的依赖,除此之外,当然还少不了SpringWeb的依赖了;我们还需要对数据库进行操作,MySQL的依赖也必不可缺dependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependencydependencygroupIdmysqlgroupIdmysqlconnectorjavaartifactIdscoperuntimescopedependency 2。逆向工程创建实体类 (1)其实这个有好几种方法,自己手动创建也行;使用IDEA中的一些插件也行;或者使用MP官网提供的代码生成模板也行。不管用哪种方法,最终要做的都是一样的,就是把项目搭起来,实体类弄起来。 (2)在这里,就直接使用MP官网提供的代码模板吧。直接在MP官网指南代码生成器(新)就能找到 (3)copy这段代码到maven工程自带的单元测试中,然后根据注释去修改一下,直接运行即可。(4)稍微解释一下怎么使用这个,其实很简单:url、username、password:即你数据库连接的地址、用户名、密码outputDir:这个就是注释的意思,输出目录嘛但注意一下,这个写到java目录即可。(可参考:D:codeestestdemosmybatissrcmainjava)parent:父包名(一般是com。xxx)moduleName:父包名下的模块名(即com。xxx。yyy这个yyy即是这个模块名了)pathInfo:后面的那个地址即是mapperxml的路径了(可参考:D:codeestestdemosmybatissrcmainresourcesmapper)addInclude:这个就更简单了,你要它帮你生成什么实体类,你就把表名往这这里填,注意的是,名字可别写错,不然识别不出来addTablePrefix:这个就是一些表的前缀在生成到Java代码中的类名时,给你去掉前缀,没有可以不管他mp逆向工程生成实体类TestvoidcontextLoads(){FastAutoGenerator。create(jdbc:mysql:localhost:3306tsmybatisdb?useUnicodetruecharacterEncodingutf8useSSLfalsenullCatalogMeansCurrenttrueserverTimezoneAsiaShanghai,root,root)。globalConfig(builder{builder。author(Peng)设置作者。enableSwagger()开启swagger模式。fileOverride()覆盖已生成文件。outputDir(D:codetesttestdemotsmybatissrcmainjava);指定输出目录})。packageConfig(builder{builder。parent(com。peng)设置父包名。moduleName(tsmybatis)设置父包模块名。pathInfo(Collections。singletonMap(OutputFile。xml,D:codetesttestdemotsmybatissrcmainresourcesmapper));设置mapperXml生成路径})。strategyConfig(builder{builder。addInclude(user)设置需要生成的表名。addTablePrefix(t,c);设置过滤表前缀})。templateEngine(newFreemarkerTemplateEngine())使用Freemarker引擎模板,默认的是Velocity引擎模板。execute();} (5)注意,这个如果没有加模板引擎运行的时候会报错,加上Freemarker依赖即可 3。大功告成之后,在你的项目中MP就会把整个项目基础模块都给搭好了,如下图: 4。注意,mapper里面的扫描在MP中并不会帮你生成,所以这个MapperScan还需要自己去加上,在启动类上面加上一个MapperScan这个注解,去扫描你的mapper文件MapperScan(value{com。peng。tsmybatis。mapper})1。2极其便利的单表操作 以下的测试都是,都是使用Postman进行测试的,在这里为了方便测试,全都是使用GetMapping去调用1。2。1增ResourceIUserServiceuserSGetMapping(add)publicbooleanadd(){UserusernewUser();user。setName(李四);user。setAge(18);returnuserService。save(user);} (1)很简单,其实就是new了一个对象扔到MP的方法里面而已,通过观察IUserService这个接口可以发现,它继承了IService且泛型里面放的就是你对应的实体类User,因此在此service下的一切MP相关的方法都是针对User这个实体类的操作 (2)因为User这个实体类是对应数据库中的User表的,所以需要注意的是当前的这个表设计中是否有哪些必填的字段,如果遗漏了(即没有set那个值到这个User对象中),那么就会报错 (3)其他就没什么需要注意的,你想添加什么内容,就往这个User对象中set什么进去就可以了。成功即返回true了,反之则false了。另外如果你想查看MP帮你执行的SQL可以在yaml或者properties中加上以下这段。我这里使用的是yaml文件配置mybatisplus:configuration:logimpl:org。apache。ibatis。logging。stdout。StdOutImpl打印mybatisplus的执行ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a 添加之后访问接口时便会有以下日志打印: (4)我这里使用的是Postman来测试这个接口,返回true则表示成功了,此时去数据库查看便可发现,多了一条name李四;age18的记录 1。2。2批增 (1)当我们有当量添加的需求时,不停的去new对象太麻烦了,因此MP为我们提供了批量添加的方法。 (2)还是很简单,只是由原来的一个对象变成了集合而已。我们只需要把需要添加的信息,收集成一个集合即可,然后把这个集合丢给MP,剩下的事情MP就会帮我们去做了,像这样:GetMapping(addBatch)publicbooleanaddBatch(){ListUserentityListnewArrayList();for(inti1;i10;i){UserusernewUser();user。setName(张三i);user。setAge(20i);entityList。add(user);}returnuserService。saveBatch(entityList);} (3)通过Postman访问http:localhost:8082addBatch这个接口后返回true,表示成功了,此时查看数据库就多了10条数据: (4)玩法很简单,只是从一个对象,变成了一个集合而已。所以MP还是很方便的,它在原来的MyBatis上增加了很多对数据库的操作方法,这些都只是它最基础的一些操作。1。2。3改、批改 (1)这个与增其实是一样的,唯一的区别是需要传一个ID,不然MP不知道你需要对哪条记录进行修改。所以只需要在上面的基础上多去set一个id就可以了,像这样:GetMapping(update)publicbooleanupdate(){UserentitynewUser();entity。setId(1);entity。setName(灵儿);entity。setAge(16);returnuserService。updateById(entity);}GetMapping(updateBatch)publicbooleanupdateBatch(){ListUserentityListnewArrayList();for(inti1;i10;i){UserusernewUser();user。setId(i1);user。setName(拜月i);user。setAge(30i);entityList。add(user);}returnuserService。updateBatchById(entityList);} (2)增和改其实本质上是差不多的,运行成功之后,查看数据库的结果就变成了这样: 1。2。4查 (1)在MP中,查就更简单了,因为在我们实际项目中用的最多的就是查询了。当然往往我们的查询会伴随着很多条件,在MP中给我们提供了条件构造器,也是能够满足到我们不写SQL的场景的,这个后续再细聊。 (2)对于单表的操作,在MP中就一个list()的方法就完成了GetMapping(list)publicListUserlist(){returnuserService。list();} (3)通过Postman访问接口后,在IDEA中可以看到MP中打印出来的日志〔图片上传失败。。。(image186b721668753721260)〕 (4)可能你会说,后面那些字段都没有数据,你不想去查出来,浪费资源,那应该怎么办呢?这时就需要我们使用条件构造器了,通过条件构造器去进行操作GetMapping(list)publicListUserlist(){QueryWrapperUserqwnewQueryWrapper();qw。select(id,name,age);qw。lambda()。select(User::getId,User::getName,User::getAge);JDK8的方法returnuserService。list(qw);} (5)注意,括号里面的字符串需要与你数据库上能够对应上,否者查不出来的,很好理解,就和自己写SQL一样,如果查询的字段表中没有,显然也是查不出来的,MP只是帮我们把SQL给写了而已12。5删、批删 (1)这个其实和修改类似的,也是需要传一个ID,不然MP不知道你要删除的是哪一条数据。 (2)还是一样,删除单条记录,只需要new一个对象然后传一个你要删除的ID进去,MP就会帮你处理了;而批删的话则是一个集合了,也是需要传ID的GetMapping(delete)publicBooleandelete(){UserentitynewUser();entity。setId(1);returnuserService。removeById(entity);}GetMapping(deleteBatch)publicbooleandeleteBatch(){ListUserentityListnewArrayList();for(inti1;i10;i){UserusernewUser();user。setId(i1);entityList。add(user);}returnuserService。removeBatchByIds(entityList);} (3)与修改稍微有点不一样的是,你不需要传修改的值过去了,只需要传你要删除的ID即可。 (4)需要注意的是,MP的这个方法是物理删除的。而在我们实际开发中,有些业务场景是逻辑删除的,也就是说我们的表中有一个类似isdelete的字段,删除时只需要修改这个字段由0变1或是由1变0即可,具体看实际需求。 (5)在MP中同样也封装了逻辑删除的一些配置,当你业务是逻辑删除时,可以在IDEA中这样去配置,告诉MP我这里使用的是逻辑删除,别真把我的记录给删除掉了很简单,只需要在逻辑删除的字段上加一个注解就可以搞定TableLogic(value0,delval1)privateIntegerisD (6)TableLogic()就是这个注解,可以去下载MP源码查看:第一个参数是未删除的值,第二个参数是已删除的值,这里就不放图片了,感兴趣的朋友可以点进去瞅瞅。 (7)除了这种配置方式外,还可以在application。yaml或者application。properties那些配置文件中进行配置,就是说,当你有好多个实体类,而好多个实体类都是逻辑删除,那么也就意味着每一个注解里面的参数都要写上value0,delval1这样一段,显然过于冗余。所以我们可以在配置文件中进行一个全局配置,像这样:mybatisplus:globalconfig:dbconfig:logicdeletefield:1删除logicnotdeletevalue:0未删除 (8)加了这个之后,MP就会对你当前的实体类所对应的表的CRUD操作都是带上逻辑删除的一个逻辑,也就是isdelete0,就是当前记录是未删除的。 (9)如果在前面开启了MP的执行日志就会发现,MP在执行CRUD的时候,最后都加上了一个WHEREisdelete0的一个判断1。3一些小扩展 (1)一般而言,我们设计表的时候,有一些字段是往往都是亘古不变的,像类似createtime、updatetime那些,像我们当前的这个表: (2)像刚刚提到的两个字段,在我们每一次添加或者修改的时候都需要去更新一下时间,一个两个还好,如果多起来的话就会发现好多代码都是重复的,特别冗余。对此MP给我提供了解决方案,可以在进行插入、修改的时候就自动帮我们进行一个处理了 (3)也和上面处理逻辑删除一样,一个注解就完事了,但这个需要去配置一下,创建一个配置类,实现MetaObjectHandler这个接口,重写他的两个方法就可以了,如下ComponentpublicclassMyMetaObjectHandlerimplementsMetaObjectHandler{OverridepublicvoidinsertFill(MetaObjectmetaObject){参数一:属性的名称参数二:你想给这个属性设置的值参数三:元对象,所有入参的MetaObject必定是entity或其子类的MetaObjectthis。setFieldValByName(createTime,LocalDateTime。now(),metaObject);this。setFieldValByName(updateTime,LocalDateTime。now(),metaObject);this。setFieldValByName(isDelete,0,metaObject);}OverridepublicvoidupdateFill(MetaObjectmetaObject){this。setFieldValByName(updateTime,LocalDateTime。now(),metaObject);}} (4)写好配置类之后,在实体类上使用TableField()这个注解和这个配置类呼应上就可以了,像这样TableField(fillFieldFill。INSERT)privateLocalDateTimecreateTTableField(fillFieldFill。INSERTUPDATE)privateLocalDateTimeupdateTTableField(fillFieldFill。INSERT)privateIntegerisD复制代码 (5)这里的意思就是说:当进行INSERT操作的时候,自动帮我createTime、updateTime字段都设置成当前时间,而isDelete则默认设置成0;当UPDATE的时候,只更改updateTime的时候改成当前更改的时间 (6)实践才是检验真理的唯一标准,咱们来试一下。我这里为了省事,就不用Postman去发请求访问接口了,直接在单元测试中进行ResourceprivateUserMapperuserMTestpublicvoidtest08(){UserusernewUser();user。setName(伏羲);user。setAge(131);intresultuserMapper。insert(user);System。out。println(result1?添加成功:添加失败);} 从控制台打印的日志可以看到,createtime,updatetime,isdelete这三个值MP默认帮我去添加了数据,而添加的数据正是我们在配置文件上设置的 (7)UPDATE也是一样的,这里就不演示了1。4小结在MP中对单表的操作是非常方便的,如果对于需要连表的一对多或多对多,需要在对应的实体类上加一些注解啥的,具体还没去研究过;因为个人觉得,在一些较为复杂的表结构中,还不如自己写SQL来得快。但是如果是对单表操作,强烈建议用MP自带的方法,谁还会写SQL呢当然目前为止演示的都是很简单的CRUD,实际操作上肯定是不一样的。因为在我们的实际操作中,可能会频繁地使用MP中的条件构造器去根据业务不同来返回数据。这个会在后面继续深入去演示一些MP中常用到的方法就是另外需要说明一下的是,上述演示的代码中,都是在Controller层中进行的。我这里是为了方便,MP中的IService中已经有CRUD的方法了,就没去到service层去操作。按照代码的规范,还是更建议去到service层中处理业务逻辑的。可能第三点会有些绕口,基础好的可能明白我说的意思了,而至于基础稍微没那么好的,既然都看到这里了,我还是在简单的演示一下标准版吧。。。比如要返回一个用户菜单(1)ControllerResourceprivateIUserServiceuserSGetMapping(userMenus)publicListUseruserMenus(){ListUserresultuserService。userMenus();如果结果不为空,返回结果;否之返回nullreturnObjectUtils。isNotEmpty(result)?result:} (2)Service,注入一个Mapper,其中也有MP自带的方法。正常来说,上面演示的都应该在这里,也就是Service层进行处理,再返回到Controller中AutowiredprivateUserMapperuserMOverridepublicListUseruserMenus(){QueryWrapperUserqwnewQueryWrapper();qw。lambda()。select(User::getId,User::getName,User::getAge);returnuserMapper。selectList(qw);} (3)如果需要写SQL,那么也是一样的,只是跳到Mapper这个接口,然后再跳到MapperXML中去写而已,当然你也可以在Mapper时使用一些MyBatis的注解(Select、Update。。。之类的),我这里直接放个图片了,就不一步步演示了 或者类似这样