学习目标
基于MyBatis Plus完成标准Dao开发
目录
🎊🎊🎊
一、MyBatis Plus简介
● MyBatis Plus(简称 MP)是基于MyBatis Plus框架基础上开发的增强型工具,旨在简化开发、提高效率
● MyBatis Plus特性(详细了解可进入官网)
— 无侵入: 只做增强不做改变,不会对现有工程产生影响
— 强大的 CRUD 操作: 内置通用 Mapper ,少量配置即可实现单表 CRUD操作
— 支持Lambda: 编写查询条件无需担心字段写错
— 支持主键自动生成
— 内置分页插件
— …
● 开发方式
—— 基于MyBatis使用MyBatis Plus
—— 基于Spring使用MyBatis Plus
—— 基于SpringBoot使用MyBatis Plus
● MyBatis Plus快速入门
数据库数据信息
选择项目依赖的技术集
实体类封装
定义数据接口,继承 BaseMapper< User > 【核心
】
package com.GY.dao;
import com.GY.domain.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao extends BaseMapper<User> {
}
测试类中注入dao接口,测试功能
二、标准数据层开发
●标准数据层CRUD功能
功能 | 自定义接口 | MP接口 |
---|---|---|
新增 | boolaen save( T t ) | int insert ( T t ) |
删除 | boolaen delete( id ) | int deleteById (Serializable id) |
修改 | boolaen update( T t ) | int updateById( T t ) |
根据id查询 | T getById ( int id ) | T selectById (Serializable id) |
查询全部 | List getAll() | List selectList() |
分页查询 | PageInfo getAll(int page,int size) | IPage< T > selectPage( IPage < T> page) |
按条件查询 | List getAll(Condition condition) | IPage< T > selectPage(Wrapper< T > queryWrapper) |
快速开发实体类
使用lombok快速开发实体类(一个Java类库,提供一组注解,简化POJO实体类开发)
● 常用注解:@Date
● 为当前类在编译期设置对应的get/set方法,toString方法,hashCode方法,equals方法等
pom文件中导入lombok jar包
实体类
package com.GY.domain;
import lombok.*;
@Data
public class User {
private Integer id;
private String name;
private Double money;
}
●分页功能
功能 | 自定义接口 | MP接口 |
---|---|---|
分页查询 | PageInfo getAll(int page,int size) | IPage< T > selectPage( IPage < T> page) |
当前数据库数据
创建MyBatis Plus 的拦截器作为Spring管理的bean
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor MP(){
// 1、定义Mp的拦截器
MybatisPlusInterceptor mp=new MybatisPlusInterceptor();
// 1、添加具体的拦截器
mp.addInnerInterceptor(new PaginationInnerInterceptor());
return mp;
}
}
测试分页查询功能
三、DQL编程控制
●条件查询
MyBatis Plus 将书写复杂的 SQL 查询进行了封装,使用编程的方式完成查询条件的组合
(使用QueryWrapper对象)
条件查询——三种格式
● 格式一:常规格式
QueryWrapper qw= new QueryWrapper();
// 查询(money<700)
qw.lt("money",700);
List<User> list=userDao.selectList(qw);
System.out.println(list);
● 格式②:链式编程格式
QueryWrapper qw= new QueryWrapper();
// 查询(600<money<900)
qw.lt(User::getMoney,900).ge(User::getMoney,600);
List<User> list=userDao.selectList(qw);
System.out.println(list);
● 格式③:lambda格式
QueryWrapper<User> qw= new QueryWrapper();
// 查询(money<600)
qw.lambda().lt(User::getMoney,600);
List<User> list=userDao.selectList(qw);
System.out.println(list);
● 格式④:lambda格式(推荐)
LambdaQueryWrapper<User> qw=new LambdaQueryWrapper<>();
// 查询(money<600或者money>900)
qw.lt(User::getMoney,600).or().ge(User::getMoney,900);
List<User> list=userDao.selectList(qw);
System.out.println(list);
条件查询——null值处理
//模拟页面传递过来的查询数据
UserQuery uq=new UserQuery();
uq.setMoney(600.0);
uq.setMoney1(700.0);
//null值判定
LambdaQueryWrapper<User> qw=new LambdaQueryWrapper<>();
//先判断第一个参数是否为true,如果为true则连接当前条件
qw.lt(uq.getMoney1()!=null,User::getMoney,uq.getMoney1());
qw.ge(uq.getMoney()!=null,User::getMoney,uq.getMoney());
List<User> list=userDao.selectList(qw);
System.out.println(list);
●查询投影
●查询结果包含模型类中部分属性
LambdaQueryWrapper<User> qw=new LambdaQueryWrapper<>();
qw.select(User::getName,User::getMoney); //——————————此格式只适用于lambda格式
List<User> list=userDao.selectList(qw);
System.out.println(list);
QueryWrapper<User> qw1=new QueryWrapper<>();
qw1.select("name","money");
List<User> list=userDao.selectList(qw1);
System.out.println(list);
●查询结果包含模型类中未定义的属性【使用QueryWrapper】
(分组查询)
QueryWrapper<User> qw2=new QueryWrapper<>();
qw2.select("count(*) as count,id");
qw2.groupBy("id");
List<Map<String ,Object>> list=userDao.selectMaps(qw2);
●查询条件设定
● 范围匹配( >、=、between )
// =匹配
LambdaQueryWrapper<User> qw=new LambdaQueryWrapper<>();
qw.eq(User::getName,"WW").eq(User::getMoney,1050.0);
User user=userDao.selectOne(qw);
● 模糊匹配( like )
// 模糊匹配
LambdaQueryWrapper<User> qw=new LambdaQueryWrapper<>();
qw.like(User::getName,"Y");
List<User> list=userDao.selectList(qw);
System.out.println(list);
● 空判定( null )
● 包含性匹配( in )
● 分组( group )
● 排序( order )
●…
更多查询条件设置可前往官网中查看
●字段映射与表名映射
问题一:表字段与编码属性设计不同步
解决方案
问题二:编码中添加了数据库中未定义的属性
解决方案
问题三:采用默认查询开放了更多的字段查看权限(实际开发中密码应不可查询)
解决方案
问题四:表名与编码开发设计不同步
解决方案
四、DML控制
● id生成策略
id生成策略控制
解决方案
所有id生成策略
了解雪花算法
http://m.baidu.com/video/page
简化id生成策略(在【application.yml】全局配置,让所有实体类使用相同策略)
表名前缀全局配置
【application.yml】
● 多记录操作
按照主键删除多条记录
@Test
void delete(){
List<Long> list=new ArrayList<>();
list.add(1L);
list.add(2L);
userDao.deleteBatchIds(list);
}
根据主键查询多条记录
@Test
void select(){
List<Long> list= Arrays.asList(new Long[]{1L,2L});
userDao.selectBatchIds(list);
}
● 逻辑删除
设置状态字段(1:删除; 0:未删除)
表数据
实体类添加逻辑字段,并设定当前字段为逻辑删除标记字段
逻辑删除成功
【application.yml】通用配置
● 乐观锁
业务并发现象带来的问题: 秒杀业务
实体类、数据库中添加字段
@Version
private Integer version;
拦截器类中添加乐观锁(配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装)
// 添加乐观锁的拦截器
mp.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mp;
五、快速开发
代码生成器
模板:MyBatis Plus提供
数据库相关配置:读取数据库获取信息
开发者自定义配置:手工配置
pom.xml中导入依赖坐标
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
创建代码生成器类
package com.GY;
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 Generator {
public static void main(String[] args) {
//创建代码生成器的对象
AutoGenerator auto=new AutoGenerator();
DataSourceConfig dataSource=new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
auto.setDataSource(dataSource);
//设置全局配置
GlobalConfig gc=new GlobalConfig();
gc.setOutputDir(System.getProperty("user.dir")+"/src/main/java"); //设置输出位置(默认D盘;*可查看源码*)
gc.setOpen(false); //设置生成完毕后是否打开生成代码所在的目录
gc.setAuthor("GY"); //设置生成作者
gc.setFileOverride(true); //设置是否覆盖原始生产的文件
gc.setMapperName("%sDao"); //设置数据层接口,%s为占位符,指代模块名称
gc.setIdType(IdType.ASSIGN_ID); //设置id生成策略
auto.setGlobalConfig(gc);
//设置包名相关配置
PackageConfig p=new PackageConfig();
p.setParent("com.GY"); //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
p.setEntity("domain"); //设置实体类包名
p.setMapper("dao"); //设置数据层包名
auto.setPackageInfo(p);
//策略设置
StrategyConfig s=new StrategyConfig();
s.setInclude("user"); //设置当前参与生成的表名,参数为可变参数
s.setTablePrefix("tb_"); //设置数据库表的前缀名称,模块名=数据库表名-前缀名(数据库表名为tb_user,自动生成后为User) 例如:User=tbl_user
s.setRestControllerStyle(true); //是否启用Rest风格
s.setVersionFieldName("version"); //设置乐观锁字段名
s.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名
s.setEntityLombokModel(true); //设置是否启用lombok
auto.setStrategy(s);
//执行代码生成器
auto.execute();
}
}
自动生成