婺源网站建设,网页制作与网站建设,wordpress自定义栏目模板,金融网站源码 asp黑马课程 文章目录1. MyBatisPlus入门1.1 MyBatisPlus入门案例步骤1#xff1a;创建spring boot工程步骤2#xff1a;配置application.yml步骤3#xff1a;创建数据库表#xff08;重点#xff09;步骤4#xff1a;编写dao层步骤5#xff1a;测试1.2 标准数据层开发标准… 黑马课程 文章目录1. MyBatisPlus入门1.1 MyBatisPlus入门案例步骤1创建spring boot工程步骤2配置application.yml步骤3创建数据库表重点步骤4编写dao层步骤5测试1.2 标准数据层开发标准CRDU使用Lombok分页功能配置MP运行日志2. DQL编程控制 —— 查2.1 条件查询的三种方式2.2 多条件查询2.3 null值处理2.4 查询投影2.5 查询条件环境准备等值查询范围查询模糊匹配排序查询2.6 映射匹配兼容性表名与编码开发设计不同步表字段与编码属性设计不同步编码中添加了数据库中未定义的属性特殊字段不参与查询如password3. DML编程控制 —— 增删改3.1 新增 —— id生成策略3.2 删除多记录删除逻辑删除 TableLogic逻辑删除 配置文件方式3.3 修改 —— 乐观锁4. 代码生成器4.1 代码生成器实现步骤1导入坐标步骤2编写代码生成器步骤3测试生成的类1. MyBatisPlus入门 MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具旨在简化开发、提供效率 开发方式 基于MyBatis使用MyBatisPlus基于Spring使用MyBatisPlus基于SpringBoot使用MyBatisPlus
1.1 MyBatisPlus入门案例 和MyBatis进行比较 步骤1创建spring boot工程
在选择依赖处勾选Web/Spring Web和SQL/MySQL Driver
注意这里没有再勾选SQL/MyBatis Framework这是因为MP并未被收录到idea的系统内置配置无法直接选择加入需要手动在pom.xml中配置添加
pom.xml中依赖如下
dependencies!-- 自动生成 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!-- 需手动添加 --dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.1/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.16/version/dependency
/dependenciesmybatis-plus-boot-starter就导入了mybatis相关坐标以及spring整合mybatis相关坐标
步骤2配置application.yml
删除原有的application.properties新建application.yml
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?useSSLfalseserverTimezoneUTCusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSources步骤3创建数据库表重点
在之前的项目中数据库表的表名没有要求 在MyBatisPlus中数据库表名一定要和domain中的实体类类名相对应 例如实体类名为Book那么数据库表名就应该是book id类型应当为 bigint(20) alter table book modify id bigint(20);对应的Book实体类的id也应该是 Long 类型
步骤4编写dao层
package com.example.dao;Mapper
public interface BookDao extends BaseMapperBook {
}只需要继承 BaseMapperBook无需写SQL注解
步骤5测试
package com.example;SpringBootTest
class MybatisplusApplicationTests {Autowiredprivate BookDao bookDao;Testvoid testGetAll(){ListBook bookList bookDao.selectList(null);System.out.println(bookList);}
}即便BookDao里面没有写方法但使用bookDao时依然会发现许多方法可供使用MP提供了默认的一些简单的增删改查方法从而无需自己编写
1.2 标准数据层开发
标准CRDU使用 package com.example.dao;Mapper
public interface BookDao extends BaseMapperBook {
}package com.example;SpringBootTest
class MybatisplusApplicationTests {Autowiredprivate BookDao bookDao;Testvoid testSave(){Book book new Book();book.setType(kk);book.setName(kk);book.setDescription(kk);bookDao.insert(book);}Testvoid testDelete(){bookDao.deleteById(1619646956185972738L);}Testvoid testUpdate(){Book book new Book();book.setId(1L);book.setType(kk2);bookDao.updateById(book);}Testvoid testGetById(){Book book bookDao.selectById(1L);System.out.println(book);}Testvoid testGetAll(){ListBook bookList bookDao.selectList(null);System.out.println(bookList);}}Lombok
一个Java类库提供了一组注解简化POJO实体类开发
步骤1导入jar包
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.12/version
/dependency报错的话加上版本号否则不加 步骤2在实体类上加上注解
在之前都是需要手动添加getter, setter, toString等方法现在可以用以下注解替代
package com.example.domain;Setter
Getter
ToString
NoArgsConstructor
AllArgsConstructor
EqualsAndHashCode//自动生成hashCode
public class Book {private Long id;private String name;private String type;private String description;
}更进一步可以简化成
package com.example.domain;Data
public class Book {private Long id;private String name;private String type;private String description;
}Data包含除构造器外的其他方法
分页功能
步骤1编写拦截器
拦截器MP已经提供只需要将其配置成Spring管理的bean对象即可
package com.example.config;Configuration
public class MpConfig {Beanpublic MybatisPlusInterceptor mpInterceptor(){//1. 定义MP拦截器MybatisPlusInterceptor mpInterceptor new MybatisPlusInterceptor();//2. 添加具体的拦截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mpInterceptor;}
}步骤2分页查询
分页查询使用的方法是:
IPageT selectPage(IPageT page, WrapperT queryWrapper)IPage:用来构建分页查询条件第几页一页多少行Wrapper用来构建条件查询的条件目前我们没有可直接传为NullIPage返回值构建分页条件和方法的返回值都是IPage
Test
void testGetByPage(){IPage page new Page(1, 5);//查询第1页每页10行bookDao.selectPage(page, null);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());
}配置MP运行日志
在application.yml中增加
#开启MP的日志输出到控制台
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl此时有很多日志输出但许多暂时用不到需要将其删除此时可以新建一个 logback.xml如下
?xml version1.0 encodingUTF-8?
configuration
/configuration一些日志已经不再显示现在取消MybatisPlus启动banner图标在application.yml中增加内容如下
#开启MP的日志输出到控制台
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:banner: false还剩下springboot的banner如果需要将其删除在 application.yml 中配置如下
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?useSSLfalseserverTimeZoneUTCusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSourcemain:banner-mode: off#开启MP的日志输出到控制台
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:banner: false2. DQL编程控制 —— 查
bookDao.selectList(null) 查看selectList源码发现它需要一个WrapperT的参数 查看wrapperT发现其为一个抽象类
public abstract class WrapperT implements ISqlSegment {...}ctrlh 查看其继承类 其中 QueryWrapper 即是需要的实现类
2.1 条件查询的三种方式
//查询 id6 的数据
Test
void testGetAll(){//方式一按条件查询QueryWrapper qw new QueryWrapper();qw.lt(id, 6);//方式二lambda格式按条件查询QueryWrapperBook qw new QueryWrapperBook();qw.lambda().lt(Book::getId, 6);//方式三推荐lambda格式按条件查询LambdaQueryWrapperBook lqw new LambdaQueryWrapperBook();lqw.lt(Book::getId, 6);ListBook bookList bookDao.selectList(lqw);System.out.println(bookList);
}2.2 多条件查询 and 查询 //查询 id6 但 10的数据
lqw.gt(Book::getId, 6).lt(Book::getId, 10);或者 lqw.gt(Book::getId, 6);
lqw.lt(Book::getId, 10);or 查询 //查询 id3 或者 id10的数据
lqw.lt(Book::getId, 3).or().gt(Book::getId, 10);2.3 null值处理
//模拟页面传递过来的查询数据查询 5id10的数据
Long idMin null;
Long idMax 10L;LambdaQueryWrapperBook lqw new LambdaQueryWrapperBook();
//null判断先判定是否为null如果为null就不连接
lqw.lt(null ! idMax, Book::getId, idMax);
lqw.gt(null ! idMin, Book::getId, idMin);ListBook bookList bookDao.selectList(lqw);
System.out.println(bookList);2.4 查询投影 查询指定字段 //查询投影只适应lambda的格式
LambdaQueryWrapperBook lqw new LambdaQueryWrapperBook();
lqw.select(Book::getId, Book::getName, Book::getType);
ListBook bookList bookDao.selectList(lqw);//查询投影非lambda的格式
QueryWrapperBook qw new QueryWrapperBook();
qw.select(id, name, type);
ListBook bookList bookDao.selectList(qw);聚合查询 完成count、max、min、avg、sum的使用 Test
void testGetAll(){QueryWrapperBook qw new QueryWrapperBook();//1. 计算总记录数qw.select(count(*) as count, type);//2. 按type分组qw.groupBy(type);//3. 获取数据ListMapString, Object bookList bookDao.selectMaps(qw);System.out.println(bookList);
}当MyBatisPlus无法处理需要的SQL要求时仍然可以在bookDao中按老方法进行编写 2.5 查询条件
其他条件查询使用方法可以去官网的指南上查询https://baomidou.com/
环境准备 准备user数据库表User类等 数据库表
CREATE TABLE user (id bigint(20) primary key auto_increment,name varchar(32) not null,password varchar(32) not null,age int(3) not null ,tel varchar(32) not null
);
insert into user values(1,Tom,tom,3,18866668888);
insert into user values(2,Jerry,jerry,4,16688886666);
insert into user values(3,Jock,123456,41,18812345678);
insert into user values(4,玛丽,123456,15,4006184000);User实体类
package com.example.domain;Data
public class User {private Long id;private String name;private String password;private int age;private String tel;
}UserDao
package com.example.dao;Mapper
public interface UserDao extends BaseMapperUser {
}等值查询
需求根据用户名和密码查询用户信息
LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();
lqw.eq(User::getName, 玛丽).eq(User::getPassword, 123456);//实际中密码需要md5加密
User user userDao.selectOne(lqw);范围查询
LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();
lqw.between(User::getAge, 10, 50);
ListUser userList userDao.selectList(lqw);模糊匹配
LambdaQueryWrapperUser lqw new LambdaQueryWrapperUser();
lqw.like(User::getName, J);//匹配 %J%
lqw.likeLeft(User::getName, J);//匹配 %J
lqw.likeRight(User::getName, J);//匹配 J%
ListUser userList userDao.selectList(lqw);like():前后加百分号,如 %J%likeLeft():前面加百分号,如 %JlikeRight():后面加百分号,如 J%
排序查询
需求查询所有数据然后按照id降序
LambdaQueryWrapperUser lqw new LambdaQueryWrapper();
/*** condition 条件返回boolean当condition为true进行排序如果为false则不排序* isAsc:是否为升序true为升序false为降序* columns需要操作的列* 下面表示进行排序升序排序字段是age*/
lqw.orderBy(true, true, User::getAge);
ListUser userList userDao.selectList(lqw);2.6 映射匹配兼容性
表名与编码开发设计不同步 准备将数据库表user修改为 tbl_user以进行演示 alter table user rename to tbl_user;此时数据库表名为tbl_user实体类为UserMP将不能正确识别 只需要在User实体类上添加TableName注解即可
Data
TableName(tbl_user)
public class User {private Long id;private String name;private String password;private int age;private String tel;
}如果希望对所有实体类都进行这样的替换可以用全局配置替换TableName
#替换所有实体类对应的表名
mybatis-plus:global-config:db-config:table-prefix: tbl_user表字段与编码属性设计不同步 准备将数据库表tbl_user中的字段password改为pwd alter table user change password pwd varchar(32) not null;只需要在User实体类对应字段加上TableField注解即可
此时数据库表名为tbl_user实体类为UserMP将不能正确识别
Data
public class User {private Long id;private String name;TableField(value pwd)private String password;private int age;private String tel;
}编码中添加了数据库中未定义的属性
例如在插入数据时User实体类中有一个online属性但数据库表user中没有这个字段此时将报错解决方法如下
TableField(exist false)
Data
public class User {private Long id;private String name;private String password;private int age;private String tel;TableField(exist false)private Integer online;
}特殊字段不参与查询如password
password将不参与查询需要隐藏起来
Data
public class User {private Long id;private String name;TableField(value pwd, select false)private String password;private int age;private String tel;
}这样设置后查询后password字段将为空
3. DML编程控制 —— 增删改
3.1 新增 —— id生成策略
Data
public class User {TableId(type IdType.AUTO)private Long id;
}如果希望设置所有实体类的id生成策略需要在application.yml文件中配置
#设置id生成策略
mybatis-plus:global-config:db-config:id-type: assign_idIdType有以下几种
Auto数据库id自增NONE不设置id生成策略INPUT用户手工输入idASSIGN_ID(默认)雪花算法生成id(可兼容数值型与字符串型)ASSIGN_UUID以UUID生成算法作为id生成策略其他的几个策略 ID_WORKER, ID_WORKER_STR, UUID 均已过时都将被ASSIGN_ID和ASSIGN_UUID代替掉。
雪花算法
生成一个64位的二进制数字及Long的大小 1bit不用因为二进制中最高位是符号位1表示负数0表示正数。生成的id一般都是用整数所以最高位固定为0 41bit-时间戳用来记录时间戳毫秒级 10bit-工作机器id用来记录工作机器id其中高位5bit是数据中心ID其取值范围0-31 低位5bit是工作节点ID其取值范围0-31两个组合起来最多可以容纳1024个节点 序列号占用12bit每个节点每毫秒0开始不断累加最多可以累加到4095一共可以产生4096个ID
3.2 删除
多记录删除
deleteBatchIds
ListLong list new ArrayList();
list.add(1619725419349172225L);
list.add(6L);
list.add(5L);
userDao.deleteBatchIds(list);同理也可以多数据查询selectBatchIds
逻辑删除 TableLogic 场景 人员表删除了人员zhangsan 订单表zhangsan对应的订单order1order2成为脏数据或者跟着一起被删除因此无法被读取 结果之后年度汇总发现订单数量对不上 解决方案逻辑标记 逻辑删除
为数据设置是否可用状态字段 deleted删除时设置状态字段为不可用状态数据保留在数据库中执行的是update操作
使用 TableLogic注解 标注 删除标识字段设置了标识字段也不会影响 select 语句因此此后在查询时会自动添加如 where selected0如果设置了标识字段又想看到已被删除的数据那么需要自己写sql语句
步骤1为数据库表增加逻辑删除字段 deleted设置默认值为0未删除
alter table user add deleted int default 0;步骤2在实体类User中增加删除标识字段deleted
Data
public class User {private Long id;private String name;TableField(select false)private String password;private int age;private String tel;//增加删除字段value表示未删除delval表示已删除TableLogic(value 0, delval 1)private Integer deleted;
}步骤3运行删除方法
userDao.deleteById(1L);发现执行的是update语句且数据库该条数据仍存在 逻辑删除 配置文件方式
在 User实体类 中添加删除字段
private Integer deleted;在 application.yml 中配置
#配置删除字段
mybatis-plus:global-config:db-config:logic-delete-field: deletedlogic-not-delete-value: 0logic-delete-value: 13.3 修改 —— 乐观锁 这里的方案适用于小系统并发在2000以下 悲观锁每次使用共享资源前先上锁乐观锁通常是在表里加一个版本或时间戳要更新前检查一下自己保存的版本和表现在的版本对比如果不一样说明被更改过了于是通知操作者重新操作
步骤1在数据库中增加列version标记当前版本号
alter table user add version int default 1;步骤2在实体类中添加字段 version并添加注解Version
package com.example.domain;Data
public class User {private Long id;private String name;TableField(select false)private String password;private int age;private String tel;//增加删除字段value表示未删除delval表示已删除TableLogic(value 0, delval 1)private Integer deleted;//增加版本字段Versionprivate Integer version;
}步骤3添加乐观锁的拦截器
package com.example.config;Configuration
public class MpConfig {Beanpublic MybatisPlusInterceptor mpInterceptor(){//1. 定义MP拦截器MybatisPlusInterceptor mpInterceptor new MybatisPlusInterceptor();//2. 添加之前的分页拦截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());//3. 添加乐观锁拦截器//作用修改时将在SQL语句中添加 set versionversion1mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mpInterceptor;}
}步骤4测试
//1. 通过要修改的数据id将当前的数据查询处理
User user userDao.selectById(2L);
//2. 修改属性值
user.setName(Lili);
//3. 进行修改
userDao.updateById(user);在执行前表中该条数据的version是1执行后version为2
一定要获取数据这样来获取到当前的版本号修改时会将自己目前的版本号和数据库版本号比对来判断在该条数据是否被修改过
步骤5模拟并发情况
Test
void testUpdate(){//1. user1和user2同时访问第1条数据User user1 userDao.selectById(4L); //version 1;User user2 userDao.selectById(4L); //version 1;//2. user2对第1条数据进行了修改user2.setName(user2);userDao.updateById(user2); //version 2;//3. user1此时再对第1条数据进行修改失败user1.setName(user1);userDao.updateById(user1);
}user1更新失败因为它的version1而数据库该条数据已经变为 version2 此时user1需要重新操作再获取一次数据然后再更新
4. 代码生成器
像是BookDaoUserDao这些类都有相似的结构可以抽取出来做成模板这也就是代码生成器的原理
模板MyBatisPlus提供可以自己提供但是麻烦不建议数据库相关配置读取数据库获取表和字段信息开发者自定义配置手工配置比如ID生成策略
4.1 代码生成器实现
步骤1导入坐标
dependencies!-- spring webmvc --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- mysql --dependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependency!-- test --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!-- mybatisplus --dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.1/version/dependency!-- druid --dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.16/version/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
/dependencies步骤2编写代码生成器
package com.example;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;public class CodeGenerator {public static void main(String[] args){//1. 定义一个自动生成器对象AutoGenerator autoGenerator new AutoGenerator();//2. 设置数据源DataSourceConfig dataSource new DataSourceConfig();dataSource.setDriverName(com.mysql.jdbc.Driver);dataSource.setUrl(jdbc:mysql://localhost:3306/ssm_db?useSSLfalseserverTimezoneUTC);dataSource.setUsername(root);dataSource.setPassword(123456);autoGenerator.setDataSource(dataSource);//3. 设置全局配置GlobalConfig globalConfig new GlobalConfig();globalConfig.setOutputDir(System.getProperty(user.dir)/src/main/java);//设置生成的文件的位置为当前项目的java目录下globalConfig.setOpen(false);//设置生成完毕后是否打开生成代码所在的目录globalConfig.setAuthor(unknown);//设置作者globalConfig.setFileOverride(true);//设置是否覆盖原始生成的文件globalConfig.setMapperName(%sDao);//设置数据层接口名%s为占位符指代模块名称默认为 %sMapperglobalConfig.setIdType(IdType.ASSIGN_ID);//设置Id生成策略autoGenerator.setGlobalConfig(globalConfig);//4. 设置包名相关配置PackageConfig packageConfig new PackageConfig();packageConfig.setParent(com.example);//设置生成的包名与setOutputDir的位置不冲突二者叠加组成完整路径packageConfig.setEntity(domain);//设置实体类包名packageConfig.setMapper(dao);//设置数据层包名autoGenerator.setPackageInfo(packageConfig);//5. 策略配置核心StrategyConfig strategyConfig new StrategyConfig();
// strategyConfig.setInclude(tbl_table1, tbl_table2);//生成指定的表必须要存在strategyConfig.setTablePrefix(tbl_);//去掉前缀如数据库表名为tbl_book那么生成的dao就为BookDao否则为Tbl_bookDaostrategyConfig.setRestControllerStyle(true);//设置是否启用RESTful风格strategyConfig.setEntityLombokModel(true);//设置是否启用LombokstrategyConfig.setLogicDeleteFieldName(deleted);//设置逻辑删除字段名strategyConfig.setVersionFieldName(version);//设置乐观锁字段autoGenerator.setStrategy(strategyConfig);//6. 执行生成操作autoGenerator.execute();}
}dao层生成的类还需要添加上 Mapper 注解
步骤3测试生成的类 注意在使用代码生成器时application.yml中的内容可以为空 但是如果要在测试中使用方法需要在application.yml中补齐dataSource的配置
代码生成器生成的结果如上在Test类中测试
SpringBootTest
class MybatisplusApplicationTests {Autowiredprivate IUserService userService;Testvoid contextLoads(){User user userService.getById(2L);System.out.println(user);}
}