网站建设好处网站空间托管

当前位置: 首页 > news >正文

网站建设好处,网站空间托管,找人做网站如何担保,网站内链调整MyBatisPlus详解 一、标准数据层开发 MyBatisPlus#xff08;简称MP#xff09;是基于MyBatis框架基础上开发的增强型工具#xff0c;旨在简化开发、提高效率 MyBatisPlus的官网为:https://mp.baomidou.com/
1.1 标准CRUD 1.2 新增 int insert (T t)T:泛型#xff0c…MyBatisPlus详解 一、标准数据层开发 MyBatisPlus简称MP是基于MyBatis框架基础上开发的增强型工具旨在简化开发、提高效率 MyBatisPlus的官网为:https://mp.baomidou.com/
1.1 标准CRUD 1.2 新增 int insert (T t)T:泛型新增用来保存新增数据 int:返回值新增成功后返回1没有新增成功返回的是0
在测试类中进行新增操作: SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;Testvoid testSave() {User user new User();user.setName(yyds);user.setPassword(yyds);user.setAge(12);user.setTel(10086);userDao.insert(user);} }执行测试后数据库表中就会添加一条数据。但是数据中的主键ID有点长这是主键ID生成策略决定的。 1.3 删除 int deleteById (Serializable id)Serializable参数类型 思考:参数类型为什么是一个序列化类? String和Number是Serializable的子类Number又是Float,Double,Integer等类的父类能作为主键的数据类型都已经是Serializable的子类MP使用Serializable作为参数类型就好比我们可以用Object接收任何数据类型一样。 int:返回值类型数据删除成功返回1未删除数据返回0。
在测试类中进行操作: SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;Testvoid testDelete() {userDao.deleteById(1401856123725713409L);} } 1.4 修改 int updateById(T t);T:泛型需要修改的数据内容注意因为是根据ID进行修改所以传入的对象中需要有ID属性值 int:返回值修改成功后返回1未修改数据返回0
在测试类中进行新增操作: SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;Testvoid testUpdate() {User user new User();user.setId(1L);user.setName(Tom888);user.setPassword(tom888);userDao.updateById(user);} }说明: 修改的时候只修改实体对象中有值的字段。 1.5 根据ID查询 T selectById (Serializable id)Serializable参数类型,主键ID的值T:根据ID查询只会返回一条数据 SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetById() {User user userDao.selectById(2L);System.out.println(user);} }1.6 查询所有 ListT selectList(WrapperT queryWrapper)Wrapper用来构建条件查询的条件目前我们没有可直接传为NullList:因为查询的是所有所以返回的数据是一个集合 SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll() {ListUser userList userDao.selectList(null);System.out.println(userList);} }我们所调用的方法都是来自于DAO接口继承的BaseMapper类中。里面的方法有很多。 1.7 分页查询 分页查询使用的方法是: IPageT selectPage(IPageT page, WrapperT queryWrapper)IPage:用来构建分页查询条件Wrapper用来构建条件查询的条件目前我们没有可直接传为NullIPage:返回值你会发现构建分页条件和方法的返回值都是IPage IPage是一个接口我们需要找到它的实现类来构建它有一个实现类为Page。 步骤1:调用方法传入参数获取返回值 SpringBootTest class Mybatisplus01QuickstartApplicationTests {Autowiredprivate UserDao userDao;//分页查询Testvoid testSelectPage(){//1 创建IPage分页对象,设置分页参数,1为当前页码3为每页显示的记录数IPageUser pagenew Page(1,3);//2 执行分页查询userDao.selectPage(page,null);//3 获取分页结果System.out.println(当前页码值page.getCurrent());System.out.println(每页显示数page.getSize());System.out.println(一共多少页page.getPages());System.out.println(一共多少条数据page.getTotal());System.out.println(数据page.getRecords());} }步骤2:设置分页拦截器 这个拦截器MP已经为我们提供好了我们只需要将其配置成Spring管理的bean对象即可。 Configuration public class MybatisPlusConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){//1 创建MybatisPlusInterceptor拦截器对象MybatisPlusInterceptor mpInterceptornew MybatisPlusInterceptor();//2 添加分页拦截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mpInterceptor;} }步骤3:运行测试程序 如果想查看MP执行的SQL语句可以修改application.yml配置文件 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印SQL日志到控制台二、DQL编程控制 2.1 条件查询 2.1.1 条件查询的类 MyBatisPlus将书写复杂的SQL查询条件进行了封装使用编程的形式完成查询条件的组合。 这个我们在前面都有见过比如查询所有和分页查询的时候都有看到过一个Wrapper类这个类就是用来构建查询条件的如下图所示: 2.1.2 环境构建 创建一个SpringBoot项目 pom.xml中添加对应的依赖 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.5.0/version/parentgroupIdcom.yyds/groupIdartifactIdmybatisplus_02_dql/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.1/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.16/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project 编写UserDao接口 Mapper public interface UserDao extends BaseMapperUser { }编写模型类 Data public class User {private Long id;private String name;private String password;private Integer age;private String tel; }编写引导类 SpringBootApplication public class Mybatisplus02DqlApplication {public static void main(String[] args) {SpringApplication.run(Mybatisplus02DqlApplication.class, args);}}编写配置文件 # dataSource spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezoneUTCusername: rootpassword: root

mp日志

mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl编写测试类 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){ListUser userList userDao.selectList(null);System.out.println(userList);} }application.yml添加如下内容: # mybatis-plus日志控制台输出 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:banner: off # 关闭mybatisplus启动图标取消SpringBoot的log打印 application.yml添加如下内容: spring:main:banner-mode: off # 关闭SpringBoot启动图标(banner)2.1.3 构建条件查询 在进行查询的时候我们的入口是在Wrapper这个类上因为它是一个接口所以我们需要去找它对应的实现类关于实现类也有很多说明我们有多种构建查询条件对象的方式 先来看第一种:QueryWrapper SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){QueryWrapper qw new QueryWrapper();qw.lt(age,18);ListUser userList userDao.selectList(qw);System.out.println(userList);} }lt: 小于() ,最终的sql语句为 SELECT id,name,password,age,tel FROM user WHERE (age ?)第一种方式介绍完后有个小问题就是在写条件的时候容易出错比如age写错就会导致查询不成功 接着来看第二种:QueryWrapper的基础上使用lambda SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){QueryWrapperUser qw new QueryWrapperUser();qw.lambda().lt(User::getAge, 10);//添加条件ListUser userList userDao.selectList(qw);System.out.println(userList);} }User::getAget,为lambda表达式中的类名::方法名最终的sql语句为: SELECT id,name,password,age,tel FROM user WHERE (age ?)注意: 构建LambdaQueryWrapper的时候泛型不能省。 此时我们再次编写条件的时候就不会存在写错名称的情况但是qw后面多了一层lambda()调用 接着来看第三种:LambdaQueryWrapper SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.lt(User::getAge, 10);ListUser userList userDao.selectList(lqw);System.out.println(userList);} }这种方式就解决了上一种方式所存在的问题。 2.1.4 多条件构建 学完了三种构建查询对象的方式每一种都有自己的特点所以用哪一种都行刚才都是一个条件那如果有多个条件该如何构建呢? 需求:查询数据库表中年龄在10岁到30岁之间的用户信息 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.lt(User::getAge, 30);lqw.gt(User::getAge, 10);ListUser userList userDao.selectList(lqw);System.out.println(userList);} }gt大于(),最终的SQL语句为 SELECT id,name,password,age,tel FROM user WHERE (age ? AND age ?)构建多条件的时候可以支持链式编程 LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser(); lqw.lt(User::getAge, 30).gt(User::getAge, 10); ListUser userList userDao.selectList(lqw); System.out.println(userList);需求:查询数据库表中年龄小于10或年龄大于30的数据 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);ListUser userList userDao.selectList(lqw);System.out.println(userList);} }or()就相当于我们sql语句中的or关键字,不加默认是and最终的sql语句为: SELECT id,name,password,age,tel FROM user WHERE (age ? OR age ?)3.1.5 null判定 需求:查询数据库表中根据输入年龄范围来查询符合条件的记录 用户在输入值的时候 ​ 如果只输入第一个框说明要查询大于该年龄的用户 ​ 如果只输入第二个框说明要查询小于该年龄的用户 ​ 如果两个框都输入了说明要查询年龄在两个范围之间的用户 思考第一个问题后台如果想接收前端的两个数据该如何接收? 我们可以使用两个简单数据类型也可以使用一个模型类但是User类中目前只有一个age属性,如: Data public class User {private Long id;private String name;private String password;private Integer age;private String tel; }方案一:添加属性age2,这种做法可以但是会影响到原模型类的属性内容 Data public class User {private Long id;private String name;private String password;private Integer age;private String tel;private Integer age2; }方案二:新建一个模型类,让其继承User类并在其中添加age2属性UserQuery在拥有User属性后同时添加了age2属性。 Data public class User {private Long id;private String name;private String password;private Integer age;private String tel; }Data public class UserQuery extends User {private Integer age2; }环境准备好后我们来实现下刚才的需求 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){//模拟页面传递过来的查询数据UserQuery uq new UserQuery();uq.setAge(10);uq.setAge2(30);LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();if(null ! uq.getAge2()){lqw.lt(User::getAge, uq.getAge2());}if( null ! uq.getAge()) {lqw.gt(User::getAge, uq.getAge());}ListUser userList userDao.selectList(lqw);System.out.println(userList);} }上面的写法可以完成条件为非空的判断但是问题很明显如果条件多的话每个条件都需要判断代码量就比较大来看MP给我们提供的简化方式 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){//模拟页面传递过来的查询数据UserQuery uq new UserQuery();uq.setAge(10);uq.setAge2(30);LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.lt(null!uq.getAge2(),User::getAge, uq.getAge2());lqw.gt(null!uq.getAge(),User::getAge, uq.getAge());ListUser userList userDao.selectList(lqw);System.out.println(userList);} }2.2 查询投影 2.2.1 查询指定字段 目前我们在查询数据的时候什么都没有做默认就是查询表中所有字段的内容我们所说的查询投影即不查询所有字段只查询出指定内容的数据。 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.select(User::getId,User::getName,User::getAge);ListUser userList userDao.selectList(lqw);System.out.println(userList);} }select(…)方法用来设置查询的字段列可以设置多个最终的sql语句为: SELECT id,name,age FROM user如果使用的不是lambda就需要手动指定字段 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){QueryWrapperUser lqw new QueryWrapperUser();lqw.select(id,name,age,tel);ListUser userList userDao.selectList(lqw);System.out.println(userList);} }2.2.2 聚合查询 需求:聚合函数查询完成count、max、min、avg、sum的使用 count:总记录数 max:最大值 min:最小值 avg:平均值 sum:求和 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){QueryWrapperUser lqw new QueryWrapperUser();//lqw.select(count() as count);//SELECT count() as count FROM user//lqw.select(max(age) as maxAge);//SELECT max(age) as maxAge FROM user//lqw.select(min(age) as minAge);//SELECT min(age) as minAge FROM user//lqw.select(sum(age) as sumAge);//SELECT sum(age) as sumAge FROM userlqw.select(avg(age) as avgAge);//SELECT avg(age) as avgAge FROM userListMapString, Object userList userDao.selectMaps(lqw);System.out.println(userList);} }为了在做结果封装的时候能够更简单我们将上面的聚合函数都起了个名称方面后期来获取这些数据 2.2.3 分组查询 需求:分组查询完成 group by的查询使用 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){QueryWrapperUser lqw new QueryWrapperUser();lqw.select(count() as count,tel);lqw.groupBy(tel);ListMapString, Object list userDao.selectMaps(lqw);System.out.println(list);} }groupBy为分组最终的sql语句为 SELECT count() as count,tel FROM user GROUP BY tel注意: 聚合与分组查询无法使用lambda表达式来完成MP只是对MyBatis的增强如果MP实现不了我们可以直接在DAO接口中使用MyBatis的方式实现 2.3 查询条件 MP的查询条件有很多: 范围匹配 、 、between模糊匹配like空判定null包含性匹配in分组group排序order…… 2.3.1 等值查询 需求:根据用户名和密码查询用户信息 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.eq(User::getName, Jerry).eq(User::getPassword, jerry);User loginUser userDao.selectOne(lqw);System.out.println(loginUser);} }eq() 相当于 ,对应的sql语句为 SELECT id,name,password,age,tel FROM user WHERE (name ? AND password ?)selectList查询结果为多个或者单个 selectOne:查询结果为单个
2.3.2 范围查询 需求:对年龄进行范围查询使用lt()、le()、gt()、ge()、between()进行范围查询 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.between(User::getAge, 10, 30);//SELECT id,name,password,age,tel FROM user WHERE (age BETWEEN ? AND ?)ListUser userList userDao.selectList(lqw);System.out.println(userList);} }gt():大于()ge():大于等于()lt():小于()lte():小于等于()between():between ? and ? 2.3.3 模糊查询 需求:查询表中name属性的值以J开头的用户信息,使用like进行模糊查询 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();lqw.likeLeft(User::getName, J);//SELECT id,name,password,age,tel FROM user WHERE (name LIKE ?J)ListUser userList userDao.selectList(lqw);System.out.println(userList);} }like():前后加百分号,如 %J%likeLeft():前面加百分号,如 %JlikeRight():后面加百分号,如 J% 2.3.4 排序查询 需求:查询所有数据然后按照id降序 SpringBootTest class Mybatisplus02DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetAll(){LambdaQueryWrapperUser lwq new LambdaQueryWrapper();/*** condition 条件返回boolean当condition为true进行排序如果为false则不排序* isAsc:是否为升序true为升序false为降序* columns需要操作的列*/lwq.orderBy(true,false, User::getId);userDao.selectList(lw} }除了上面介绍的这几种查询条件构建方法以外还会有很多其他的方法比如isNull,isNotNull,in,notIn等等方法可供选择具体参考官方文档的条件构造器来学习使用具体的网址为: https://mp.baomidou.com/guide/wrapper.html#abstractwrapper 2.4 映射匹配兼容性 前面我们已经能从表中查询出数据并将数据封装到模型类中这整个过程涉及到一张表和一个模型类: 问题1:表字段与编码属性设计不同步 当表的列名和模型类的属性名发生不一致就会导致数据封装不到模型对象这个时候就需要其中一方做出修改那如果前提是两边都不能改又该如何解决? MP给我们提供了一个注解TableField,使用该注解可以实现模型类属性名和表的列名之间的映射关系 问题2:编码中添加了数据库中未定义的属性 当模型类中多了一个数据库表不存在的字段就会导致生成的sql语句中在select的时候查询了数据库不存在的字段程序运行就会报错错误信息为: Unknown column ‘多出来的字段名称’ in ‘field list’ 具体的解决方案用到的还是TableField注解它有一个属性叫exist设置该字段是否在数据库表中存在如果设置为false则不存在生成sql语句查询的时候就不会再查询该字段了。 问题3采用默认查询开放了更多的字段查看权限 查询表中所有的列的数据就可能把一些敏感数据查询到返回给前端这个时候我们就需要限制哪些字段默认不要进行查询。解决方案是TableField注解的一个属性叫select该属性设置默认是否需要查询该字段的值true(默认值)表示默认查询该字段false表示默认不查询该字段。 知识点1TableField 名称TableField类型属性注解位置模型类属性定义上方作用设置当前属性对应的数据库表中的字段关系相关属性value(默认)设置数据库表字段名称exist:设置属性在数据库表字段中是否存在默认为true此属性不能与value合并使用select:设置属性是否参与查询此属性与select()映射配置不冲突 问题4:表名与编码开发设计不同步 该问题主要是表的名称和模型类的名称不一致导致查询失败这个时候通常会报如下错误信息: Table ‘databaseName.tableNaem’ doesn’t exist,翻译过来就是数据库中的表不存在。 解决方案是使用MP提供的另外一个注解TableName来设置表与模型类之间的对应关系。
知识点2TableName 名称TableName类型类注解位置模型类定义上方作用设置当前类对应于数据库表关系相关属性value(默认)设置数据库表名称 三、DML编程控制 查询相关的操作我们已经介绍完了紧接着我们需要对另外三个增删改进行内容的讲解。挨个来说明下首先是新增(insert)中的内容。 3.1 id生成策略控制 不同的表应用不同的id生成策略 日志自增1,2,3,4……购物订单特殊规则FQ23948AK3843外卖单关联地区日期等信息10 04 20200314 34 91关系表可省略id……
不同的业务采用的ID生成方式应该是不一样的那么在MP中都提供了哪些主键生成策略以及我们该如何进行选择? 在这里我们又需要用到MP的一个注解叫TableId(TableId(type IdType.INPUT)) 知识点1TableId 名称TableId类型属性注解位置模型类中用于表示主键的属性定义上方作用设置当前类中主键属性的生成策略相关属性value(默认)设置数据库表主键名称type:设置主键属性的生成策略值查照IdType的枚举值 从源码中可以看到除了AUTO这个策略以外还有如下几种生成策略: NONE: 不设置id生成策略INPUT:用户手工输入idASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)ASSIGN_UUID:以UUID生成算法作为id生成策略其他的几个策略均已过时都将被ASSIGN_ID和ASSIGN_UUID代替掉。 分布式ID是什么? 当数据量足够大的时候一台数据库服务器存储不下这个时候就需要多台数据库服务器进行存储比如订单表就有可能被存储在不同的服务器上如果用数据库表的自增主键因为在两台服务器上所以会出现冲突这个时候就需要一个全局唯一ID,这个ID就是分布式ID。 介绍了这些主键ID的生成策略我们以后该用哪个呢? NONE: 不设置id生成策略MP不自动生成约等于INPUT,所以这两种方式都需要用户手动设置但是手动设置第一个问题是容易出现相同的ID造成主键冲突为了保证主键不冲突就需要做很多判定实现起来比较复杂AUTO:数据库ID自增,这种策略适合在数据库服务器只有1台的情况下使用,不可作为分布式ID使用ASSIGN_UUID:可以在分布式的情况下使用而且能够保证唯一但是生成的主键是32位的字符串长度过长占用空间而且还不能排序查询性能也慢ASSIGN_ID:可以在分布式的情况下使用生成的是Long类型的数字可以排序性能也高但是生成的策略和服务器时间有关如果修改了系统时间就有可能导致出现重复主键综上所述每一种主键策略都有自己的优缺点根据自己项目业务的实际情况来选择使用才是最明智的选择。 简化配置 mybatis-plus:global-config:db-config:id-type: assign_id配置完成后每个模型类的主键ID策略都将成为assign_id. 数据库表与模型类的映射关系 MP会默认将模型类的类名名首字母小写作为表名使用假如数据库表的名称都以tbl_开头那么我们就需要将所有的模型类上添加TableName如: 配置起来还是比较繁琐简化方式为在配置文件中配置如下内容: mybatis-plus:global-config:db-config:table-prefix: tbl_设置表的前缀内容这样MP就会拿 tbl_加上模型类的首字母小写就刚好组装成数据库的表名。 3.2 多记录操作 如何实现多条删除我们找找对应的API方法 int deleteBatchIds(Param(Constants.COLLECTION) Collection? extends Serializable idList);需求:根据传入的id集合将数据库表中的数据删除掉。 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testDelete(){//删除指定多条数据ListLong list new ArrayList();list.add(1402551342481838081L);list.add(1402553134049501186L);list.add(1402553619611430913L);userDao.deleteBatchIds(list);} }执行成功后数据库表中的数据就会按照指定的id进行删除。 除了按照id集合进行批量删除也可以按照id集合进行批量查询还是先来看下API ListT selectBatchIds(Param(Constants.COLLECTION) Collection? extends Serializable idList);方法名称翻译为:查询根据ID 批量查询参数是一个集合可以存放多个id值。 需求根据传入的ID集合查询用户信息 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testGetByIds(){//查询指定多条数据ListLong list new ArrayList();list.add(1L);list.add(3L);list.add(4L);userDao.selectBatchIds(list);} }查询结果就会按照指定传入的id值进行查询 3.3 逻辑删除 MP中逻辑删除具体该如何实现? 步骤1:修改数据库表添加deleted列 字段名可以任意内容也可以自定义比如0代表正常1代表删除可以在添加列的同时设置其默认值为0正常。 步骤2:实体类添加属性 (1)添加与数据库表的列对应的一个属性名名称可以任意如果和数据表列名对不上可以使用TableField进行关系映射如果一致则会自动对应。 (2)标识新增的字段为逻辑删除字段使用TableLogic Data //TableName(tbl_user) 可以不写是因为配置了全局配置 public class User {TableId(type IdType.ASSIGN_UUID)private String id;private String name;TableField(valuepwd,selectfalse)private String password;private Integer age;private String tel;TableField(existfalse)private Integer online;TableLogic(value0,delval1)//value为正常数据的值delval为删除数据的值private Integer deleted; }步骤3:运行删除方法 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testDelete(){userDao.deleteById(1L);} }逻辑删除最后走的是update操作会将指定的字段修改成删除状态对应的值。 思考 逻辑删除对查询有没有影响呢? 执行查询操作 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testFind(){System.out.println(userDao.selectList(null));} }可想而知MP的逻辑删除会将所有的查询都添加一个未被删除的条件也就是已经被删除的数据是不应该被查询出来的。 如果还是想把已经删除的数据都查询出来该如何实现呢? Mapper public interface UserDao extends BaseMapperUser {//查询所有数据包含已经被删除的数据Select(select * from tbl_user)public ListUser selectAll(); }如果每个表都要有逻辑删除那么就需要在每个模型类的属性上添加TableLogic注解如何优化? 在配置文件中添加全局配置如下: mybatis-plus:global-config:db-config:# 逻辑删除字段名logic-delete-field: deleted# 逻辑删除字面值未删除为0logic-not-delete-value: 0# 逻辑删除字面值删除为1logic-delete-value: 1知识点1TableLogic 名称TableLogic类型属性注解位置模型类中用于表示删除字段的属性定义上方作用标识该字段为进行逻辑删除的字段相关属性value逻辑未删除值delval:逻辑删除值 3.4 乐观锁 3.4.1 概念 业务并发现象带来的问题:秒杀 假如有100个商品或者票在出售为了能保证每个商品或者票只能被一个人购买如何保证不会出现超买或者重复卖对于这一类问题其实有很多的解决方案可以使用第一个最先想到的就是锁锁在一台服务器中是可以解决的但是如果在多台服务器下锁就没有办法控制比如12306有两台服务器在进行卖票在两台服务器上都添加锁的话那也有可能会导致在同一时刻有两个线程在进行卖票还是会出现并发问题我们接下来介绍的这种方式是针对于小型企业的解决方案因为数据库本身的性能就是个瓶颈如果对其并发量超过2000以上的就需要考虑其他的解决方案了。 简单来说乐观锁主要解决的问题是当要更新一条记录的时候希望这条记录没有被别人更新。 3.4.2 实现思路 乐观锁的实现方式: 数据库表中添加version列比如默认值给1第一个线程要修改数据之前取出记录时获取当前数据库中的version1第二个线程要修改数据之前取出记录时获取当前数据库中的version1第一个线程执行更新时set version newVersion where version oldVersion newVersion version1 [2]oldVersion version [1] 第二个线程执行更新时set version newVersion where version oldVersion newVersion version1 [2]oldVersion version [1] 假如这两个线程都来更新数据第一个和第二个线程都可能先执行 假如第一个线程先执行更新会把version改为2第二个线程再更新的时候set version 2 where version 1,此时数据库表的数据version已经为2所以第二个线程会修改失败假如第二个线程先执行更新会把version改为2第一个线程再更新的时候set version 2 where version 1,此时数据库表的数据version已经为2所以第一个线程会修改失败不管谁先执行都会确保只能有一个线程更新数据这就是MP提供的乐观锁的实现原理分析。 3.4.3 实现步骤 分析完步骤后具体的实现步骤如下: 步骤1:数据库表添加列 列名可以任意比如使用version,给列设置默认值为1 步骤2:在模型类中添加对应的属性 根据添加的字段列名在模型类中添加对应的属性值 Data //TableName(tbl_user) 可以不写是因为配置了全局配置 public class User {TableId(type IdType.ASSIGN_UUID)private String id;private String name;TableField(valuepwd,selectfalse)private String password;private Integer age;private String tel;TableField(existfalse)private Integer online;private Integer deleted;Versionprivate Integer version; }步骤3:添加乐观锁的拦截器 Configuration public class MpConfig {Beanpublic MybatisPlusInterceptor mpInterceptor() {//1.定义Mp拦截器MybatisPlusInterceptor mpInterceptor new MybatisPlusInterceptor();//2.添加乐观锁拦截器mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mpInterceptor;} }步骤4:执行更新操作 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testUpdate(){User user new User();user.setId(3L);user.setName(Jock666);userDao.updateById(user);} }你会发现这次修改并没有更新version字段原因是没有携带version数据。 添加version数据 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testUpdate(){User user new User();user.setId(3L);user.setName(Jock666);user.setVersion(1);userDao.updateById(user);} }你会发现我们传递的是1MP会将1进行加1然后更新回到数据库表中。 所以要想实现乐观锁首先第一步应该是拿到表中的version然后拿version当条件在将version加1更新回到数据库表中所以我们在查询的时候需要对其进行查询 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testUpdate(){//1.先通过要修改的数据id将当前数据查询出来User user userDao.selectById(3L);//2.将要修改的属性逐一设置进去user.setName(Jock888);userDao.updateById(user);} }大概分析完乐观锁的实现步骤以后我们来模拟一种加锁的情况看看能不能实现多个人修改同一个数据的时候只能有一个人修改成功。 SpringBootTest class Mybatisplus03DqlApplicationTests {Autowiredprivate UserDao userDao;Testvoid testUpdate(){//1.先通过要修改的数据id将当前数据查询出来User user userDao.selectById(3L); //version3User user2 userDao.selectById(3L); //version3user2.setName(Jock aaa);userDao.updateById(user2); //version4user.setName(Jock bbb);userDao.updateById(user); //verion3?条件还成立吗} }官方文档: https://mp.baomidou.com/guide/interceptor-optimistic-locker.html#optimisticlockerinnerinterceptor 四、快速开发 4.1 代码生成器 步骤1:创建一个Maven项目 步骤2:导入对应的jar包 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.5.1/version/parentgroupIdcom.yyds/groupIdartifactIdmybatisplus_04_generator/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version1.8/java.version/propertiesdependencies!–spring webmvc–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!–mybatisplus–dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.1/version/dependency!–druid–dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.16/version/dependency!–mysql–dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdscoperuntime/scope/dependency!–test–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!–lombok–dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.12/version/dependency!–代码生成器–dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-generator/artifactIdversion3.4.1/version/dependency!–velocity模板引擎–dependencygroupIdorg.apache.velocity/groupIdartifactIdvelocity-engine-core/artifactIdversion2.3/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project 步骤3:编写引导类 SpringBootApplication public class Mybatisplus04GeneratorApplication {public static void main(String[] args) {SpringApplication.run(Mybatisplus04GeneratorApplication.class, args);}}步骤4:创建代码生成类 public class CodeGenerator {public static void main(String[] args) {//1.获取代码生成器的对象AutoGenerator autoGenerator new AutoGenerator();//设置数据库相关配置DataSourceConfig dataSource new DataSourceConfig();dataSource.setDriverName(com.mysql.cj.jdbc.Driver);dataSource.setUrl(jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezoneUTC);dataSource.setUsername(root);dataSource.setPassword(root);autoGenerator.setDataSource(dataSource);//设置全局配置GlobalConfig globalConfig new GlobalConfig();globalConfig.setOutputDir(System.getProperty(user.dir)/mybatisplus_04_generator/src/main/java); //设置代码生成位置globalConfig.setOpen(false); //设置生成完毕后是否打开生成代码所在的目录globalConfig.setAuthor(yyds); //设置作者globalConfig.setFileOverride(true); //设置是否覆盖原始生成的文件globalConfig.setMapperName(%sDao); //设置数据层接口名%s为占位符指代模块名称globalConfig.setIdType(IdType.ASSIGN_ID); //设置Id生成策略autoGenerator.setGlobalConfig(globalConfig);//设置包名相关配置PackageConfig packageInfo new PackageConfig();packageInfo.setParent(com.aaa); //设置生成的包名与代码所在位置不冲突二者叠加组成完整路径packageInfo.setEntity(domain); //设置实体类包名packageInfo.setMapper(dao); //设置数据层包名autoGenerator.setPackageInfo(packageInfo);//策略设置StrategyConfig strategyConfig new StrategyConfig();strategyConfig.setInclude(tbluser); //设置当前参与生成的表名参数为可变参数strategyConfig.setTablePrefix(tbl); //设置数据库表的前缀名称模块名 数据库表名 - 前缀名 例如 User tbl_user - tbl_strategyConfig.setRestControllerStyle(true); //设置是否启用Rest风格strategyConfig.setVersionFieldName(version); //设置乐观锁字段名strategyConfig.setLogicDeleteFieldName(deleted); //设置逻辑删除字段名strategyConfig.setEntityLombokModel(true); //设置是否启用lombokautoGenerator.setStrategy(strategyConfig);//2.执行生成操作autoGenerator.execute();} }对于代码生成器中的代码内容我们可以直接从官方文档中获取代码进行修改 https://mp.baomidou.com/guide/generator.html 步骤5:运行程序 运行成功后会在当前项目中生成很多代码代码包含controller,servicemapper和entity 4.2 MP中Service的CRUD MP提供了一个Service接口和实现类分别是:IService和ServiceImpl,后者是对前者的一个具体实现。 以后我们自己写的Service就可以进行如下修改: public interface UserService extends IServiceUser{}Service public class UserServiceImpl extends ServiceImplUserDao, User implements UserService{}修改以后的好处是MP已经帮我们把业务层的一些基础的增删改查都已经实现了可以直接进行使用。 编写测试类进行测试: SpringBootTest class Mybatisplus04GeneratorApplicationTests {private IUserService userService;Testvoid testFindAll() {ListUser list userService.list();System.out.println(list);}}注意: mybatisplus_04_generator项目中对于MyBatis的环境是没有进行配置如果想要运行需要提取将配置文件中的内容进行完善后在运行。 思考:在MP封装的Service层都有哪些方法可以用? 查看官方文档:https://mp.baomidou.com/guide/crud-interface.html