实习 实习 MySQL+MyBatis+MyBatisPlus 李阳 2025-09-30 2025-11-24 啊啊啊啊,马上就要实习工作了,但是我的Mysql之类的一直没有怎么学过,工作肯定要用gg了,来打基础来了
一、MySQL 1.DQL
1.1 分组查询 group by
查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址 select workaddness,count(*) from emp where age 45 group by workaddness having count(*) >= 3;
1.2 排序 order by
2. 多表查询 2.1 多表查询
2.2 内连接 (查询两表的交集部分)
查询每一个员工姓名,及关联的名称
隐式内连接 select emp.name , dept.name from emp , dept where emp.dept_id = dept.id
显示内连接-INNER JOIN select e.name,d.name from emp e join dept d on e.dept_id = d.id;
2.3 左外右外链接 –外连接演示 – 1.查询emp表的所有数据,和对应的部门信息(左外连接)–表结构:emp, dept –连接条件:emp . dept_id = dept.id
select e.,d.name from emp e left join dept d on e.dept_id = d.id;
– 2.查询dept表的所有数据,和对应的员工信息(右外连接)
select d.,e.* from emp e right outer join dept d on e.dept_id = d.id;
开发中多用左外连接
2.4 自连接
–自连接 – 1.查询员工及其所属领导的名字
–表结构: emp select a.name , b.name from empIa , emp b where a.managerid = b.id;
–2.查询所有员工 emp及其领导的名字 emp ,如果员工没有领导,也需要查询出来
–表结构: emp a , emp b
select a.name ’员工“,b.name ‘领导’ from emp a left join emp b on a.managerid = b.id;
2.5 联合查询
2.6 子查询
1. 标量子查询
查询销售部的所有员工信息
select * from emp where dept_id = (select id from dept where name = ‘销售部’)
2. 列子查询
3. 行子查询
4. 表子查询
3. 窗口函数 窗口函数([参数]) OVER ( [PARTITION BY <分组列>] [ORDER BY <排序列 ASC/DESC>] [ROWS BETWEEN 开始行 AND 结束行] )
PARTITION BY 子句用于指定分组列,关键字:PARTITION BY 。ORDER BY 子句用于指定排序列,关键字ORDER BY 。ROWS BETWEEN 子句用于指定窗口的范围,关键字ROWS BETWEEN 即[开始行]、[结束行](这部分在“补充与总结”小节中作补充详细说明)。其中,ROWS BETWEEN 子句在实际中可能用得相对少一些,因此有部分参考资料的语法描述省略了ROWS BETWEEN 子句,主要侧重于PARTITION BY分组与ORDER BY排序:
3.1 聚合窗口函数 许多窗口函数的教程,通常将常用的窗口函数分为两大类:聚合窗口函数 与 专用窗口函数。聚合窗口函数的函数名与普通常用聚合函数一致,功能也一致。从使用的角度来讲,与普通聚合函数的区别在于提供了窗口函数的专属子句,来使得数据的分析与获取更简便。主要有如下几个:
函数名 作用 SUM 求和 AVG 求平均值 COUNT 求数量 MAX 求最大值 MIN 求最小值
普通聚合函数
SELECT t1.* , t2.avg_revenue FROM sales t1 LEFT JOIN ( SELECT category, AVG (revenue) AS avg_revenue FROM sales GROUP BY category ) t2 ON t1.category = t2.category ORDER BY t1.category
聚合窗口函数
SELECT sales.*, AVG( revenue ) OVER ( PARTITION BY category ) AS avg_revenue FROM sales
3.2 专用窗口函数 常见的专用窗口函数
函数名 分类 说明 RANK 排序函数 类似于排名,并列的结果序号可以重复,序号不连续 DENSE_RANK 排序函数 类似于排名,并列的结果序号可以重复,序号连续 ROW_NUMBER 排序函数 对该分组下的所有结果作一个排序,基于该分组给一个行数 PERCENT_RANK 分布函数 每行按照公式 (rank-1) / (rows-1) 进行计算 CUME_DIST 分布函数 分组内小于、等于当前 rank 值的行数 / 分组内总行数
例题:力扣178分数排名
SELECT score, DENSE_RANK () OVER (ORDER BY score DESC ) AS `rank` FROM Scores ORDER BY score DESC
4. 零碎知识点 4.1 关键字IN的用法 在 SQL 中,IN 关键字主要用于判断某个值是否在一个指定的集合(可以是值列表、子查询结果等)中,起到过滤数据的作用,以下是其详细用法:
1. 与值列表配合使用 语法:column IN (value1, value2, ..., valuen)作用:判断列 column 的值是否是 value1 到 valuen 中的某一个。示例:
SELECT * FROM Employee WHERE DepartmentId IN (1 , 2 );
2. 与子查询配合使用 语法:column IN (subquery)作用:判断列 column 的值是否在子查询返回的结果集中。示例:
SELECT * FROM Employee eWHERE (e.Salary, e.DepartmentId) IN (SELECT MAX (Salary), DepartmentId FROM Employee GROUP BY DepartmentId);
3. IN 与 NOT 结合使用 语法:column NOT IN (value1, value2, ..., valuen) 或 column NOT IN (subquery)作用:判断列 column 的值不在 指定的集合或子查询结果集中。示例:
SELECT * FROM Employee WHERE DepartmentId NOT IN (1 , 2 );
需要注意的是,当 IN 配合的子查询返回空结果集时,column IN (subquery) 会返回 FALSE;而 column NOT IN (subquery) 会因为逻辑判断的特殊性(空值参与时结果可能不符合预期),建议谨慎使用,或通过其他方式(如 LEFT JOIN + IS NULL)替代。
二、MyBatisPlus 2.1 常见注解 @TableName:用来指定表名
@TableId:用来指定表中的字段信息
@TableField:用来指定表的普通字段信息
不指定自增长默认为雪花算法
2.2 常见自定义配置
2.3 核心功能 案例1 查询出名字带o的存款大于等于1000的人的id,username
ge大于等于 gt大于 le小于大于 lt 小于
QueryWrapper.<USer> wapper =new QueryWrapper <User>() .select("id" ,"username" ,"info" ,"balance" ) .like("username" ,"o" ) .ge("balance" ,1000 ); List<User> uers =userMapper.selectList(wapper); user.forEach(System::println);
更新用户名为jack的用户的余额为2000
User user = new User ();user.setBalance(2000 ); QueryWrapper.<USer> wapper =new QueryWrapper <User>().eq("username" ,"jack" ); usermapper.update(user,wapper);
案例2 更新id为1,2,4的用户余额扣200
List<Long> ids = List.of( 1L ,2L ,4L ); Updatewrapper<User> wrapper = new Updatewrapper <User>() .setsql(balance = balance -200 ") .in(column: " id", ids); userMapper.update( null, wrapper) ;
填null,是因为UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法,允许指定SQL中的SET部分来更新。 第一个参数传 null 是为了告诉 MyBatis-Plus,更新的字段和值已经写在 UpdateWrapper 里,不需要实体对象来更新字段。 当你用 UpdateWrapper 来设置更新的字段和条件时,更新的字段和新值都是写在 UpdateWrapper 里的,这时不需要一个实体传入去覆盖字段的值。因此,entity 参数传 null,表示用 updateWrapper 里的SQL片段来执行更新。
LambdaQuerywrapper<User> wrapper = new LambdaQuerywrapper <User>() .select(User::getId,User::getUsername,User::getInfo,User::getBalance) .like(User: :getUsername,val: "o" ") .ge(User: :getBalance,val: 1000); List<User> users = userMapper.selectList(wrapper);users.forEach(System.out : :println);
2.4 自定义SQL 为编号1,2,3的用户扣减指定余额
---------------Controller------------- List<Long> ids = List.of( 1L ,2L ,4L );int amount = 200 ; Querywrapper<User> wrapper = new Querywrapper <User> ().in( column: "id" ,ids); userMapper.updateBalanceyIds(wrapper,amount) ; ----------Service-------------- void updateBalanceEy.Idis(@Param(Constants.MRAPPER) Querywrapper<User> wrapper,Par am ("amount" ) int amount);------Mapper----- <update id="updateBalanceByIds" > UPDATE tb_user SET balance = balance - #{amount} $ {ew.customsqlsegment</update>
2.5 IService
语法 public interface 方法名称 extends Iservice <实体名称>{}
public class 方法名称 extends ServiceImpl <实体名称+Mapper,实体名称> implements 接口名称{}
2.6 静态工具
普通的Isservice接口有可能会出现循环依赖的问题,这时候使用静态工具就可以解决循环依赖的问题
使用DB.lambdaQuery来实现
2.7 枚举处理器
import lombok.Getter;import com.baomidou.mybatisplus.annotation.EnumValue;@Getter public enum UserStatus { NORMAL(1 , "正常" ), FROZEN(2 , "冻结" ); @EnumValue private final int value; private final String desc; UserStatus(int value, String desc) { this .value = value; this .desc = desc; } }
配置
configuration: default-enum-type-handler: com. baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
2.8 JSON处理器
2.9 分页插件 首先,要在配置类中注册MyBatisPlus的核心插件,同时添加分页插件:
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;import com.baomidou.mybatisplus.annotation.DbType;@Configuration public class MybatisConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor () { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor (); PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor (DbType.MYSQL); pageInterceptor.setMaxLimit(1000L ); interceptor.addInnerInterceptor(pageInterceptor); return interceptor; } }
通用分页结果
import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import java.util.List;@Data @ApiModel(description = "分页结果数据") public class PageDTO <T> { @ApiModelProperty(value = "总记录数", example = "100") private Long total; @ApiModelProperty(value = "总页数", example = "10") private Integer pages; @ApiModelProperty(value = "当前页码", example = "1") private Long current; @ApiModelProperty(value = "每页显示条数", example = "10") private Long size; @ApiModelProperty(value = "分页数据列表") private List<T> records; }
通用分页工具 分页查询实体PageQuery
import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.baomidou.mybatisplus.core.metadata.OrderItem;import cn.hutool.core.util.StrUtil;@Data @ApiModel(description = "分页查询实体") public class PageQuery { @ApiModelProperty("页码") private Integer pageNo = 1 ; @ApiModelProperty("每页条数") private Integer pageSize = 5 ; @ApiModelProperty("排序字段") private String sortBy; @ApiModelProperty("是否升序") private Boolean isAsc; public <T> Page<T> toMpPage () { Page<T> page = Page.of(pageNo, pageSize); if (StrUtil.isNotBlank(sortBy)) { page.addOrder(new OrderItem (sortBy, isAsc)); } return page; } public <T> Page<T> toMpPage (OrderItem... items) { Page<T> page = Page.of(pageNo, pageSize); if (StrUtil.isNotBlank(sortBy)) { page.addOrder(new OrderItem (sortBy, isAsc)); } else if (items != null ) { page.addOrder(items); } return page; } public <T> Page<T> toMpPage (String defaultSortBy, Boolean defaultAsc) { return toMpPage(new OrderItem (defaultSortBy, defaultAsc)); } public <T> Page<T> toMpPageDefaultSortByCreateTime () { return toMpPage(new OrderItem ("create_time" , false )); } public <T> Page<T> toMpPageDefaultSortByUpdateTime () { return toMpPage(new OrderItem ("update_time" , false )); } }
分页结果PageDto
import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import org.springframework.util.CollectionUtils;import java.util.Collections;import java.util.List;@Data @ApiModel(description = "分页结果") public class PageDTO <VO> { @ApiModelProperty("总条数") private Long total; @ApiModelProperty("总页数") private Long pages; @ApiModelProperty("集合") private List<VO> list; public static <PO, VO> PageDTO<VO> of (Page<PO> page, Class<VO> clazz) { PageDTO<VO> dto = new PageDTO <>(); dto.setTotal(page.getTotal()); dto.setPages(page.getPages()); List<PO> records = page.getRecords(); if (CollectionUtils.isEmpty(records)) { dto.setList(Collections.emptyList()); return dto; } dto.setList(BeanUtil.copyToList(records, clazz)); return dto; } public static <PO, VO> PageDTO<VO> of (Page<PO> p, Function<PO, VO> converter) { PageDTO<VO> dto = new PageDTO <>(); dto.setTotal(p.getTotal()); dto.setPages(p.getPages()); List<PO> records = p.getRecords(); if (records == null || records.isEmpty()) { dto.setList(Collections.emptyList()); return dto; } dto.setList(records.stream() .map(converter) .collect(Collectors.toList())); return dto; } }
需引入 Bean 复制工具类(如 Hutool 的 BeanUtil 或 Spring 的 BeanUtils 适配工具) 需引入 MyBatis-Plus 核心包(Page 类)