《从零开始的java从入门到入土的学习生活——JavaWeb后端篇》Chapter15——JavaWeb后端篇学习记录——多表关系、多表查询、分页查询

一、多表关系

有以下三种关系:一对多,多对多,一对一

1、多表关系问题分析

在一个部门员工表下,部门数据可以直接删除,然而还有部分员工归属于该部门下,此时就出现了数据的不完整、不一致问题 。出现问题的原因是目前上述的两张表,在数据库层面,并未建立关联,所以是无法保证数据的一致性和完整性的 。想解决上述的问题呢,我们就可以通过数据库中的 外键约束 来解决。

通过SQL语句操作:

sql 复制代码
-- 创建表时指定
create table 表名(
        字段名    数据类型,
        ...
        [constraint]   [外键名称]  foreign  key (外键字段名)   references   主表 (主表列名)        
);


-- 建完表后,添加外键
alter table  表名  add constraint  外键名称  foreign key(外键字段名) references 主表(主表列名);

通过图形化界面操作:

外键约束(foreign key):保证了数据的完整性和一致性。

2、物理外键和逻辑外键

①物理外键

|--------|------------------------------------------------------------------------|
| 概念 | 使用foreign key定义外键关联另外一张表 |
| 缺点 | * 影响增、删、改的效率(需要检查外键关系)。 * 仅用于单节点数据库,不适用于分布式、集群场景。 * 容易引发数据库的死锁问题,消耗性能。 |

②逻辑外键

在业务层逻辑中,解决外键关联,通过逻辑外键,就可以很方便的解决上述问题(逻辑外键的操作过程通过代码层面(例如通过serviceimpl设置的if条件语句,如果存在/不存在,就可以/不可以执行这个操作))。在现在的企业开发中,很少会使用物理外键,都是使用逻辑外键。 甚至在一些数据库开发规范中,会明确指出禁止使用物理外键 foreign key。

二、多表查询

查询时从多张表中获取所需数据,进行多表查询时,只需要使用逗号分隔多张表即可,如: select 字段列表 from 表1, 表2,假如这样直接查询会出现很多无效的笛卡尔积(即所有的组合情况,有点数据重了),所以可以在尾部加上条件语句where

sql 复制代码
select * from emp , dept where emp.dept_id = dept.id ;

1、连接查询

①内连接

相当于查询A、B交集部分数据,语法上分为显式内连接和隐式内连接

隐式内连接:

sql 复制代码
select  字段列表   from   表1 , 表2   where  条件 ... ;

显式内连接:

sql 复制代码
select  字段列表   from   表1  [ inner ]  join 表2  on  连接条件 ... ;

在SQL语句中可以为表起别名简化书写:

sql 复制代码
select  字段列表 from 表1 as 别名1 , 表2 as  别名2  where  条件 ... ;

select  字段列表 from 表1 别名1 , 表2  别名2  where  条件 ... ;  -- as 可以省略

例子:

sql 复制代码
select e.id, e.name, d.name from emp as e , dept as d where e.dept_id = d.id and e.gender = 1 and e.salary > 8000;

**注意:**一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。

②外连接

分为左连接和右连接,左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集。右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。部分的数据。

左连接语法:

sql 复制代码
select  字段列表   from   表1  left  [ outer ]  join 表2  on  连接条件 ... ;

左外连接:以left join关键字左边的表为主表,查询主表中所有数据,以及和主表匹配的右边表中的数据

右连接语法:

sql 复制代码
select  字段列表   from   表1  right  [ outer ]  join 表2  on  连接条件 ... ;

右外连接:以right join关键字右边的表为主表,查询主表中所有数据,以及和主表匹配的左边表中的数据

**注意:**左外连接和右外连接是可以相互替换的,只需要调整连接查询时SQL语句中表的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。

③子查询

SQL语句中嵌套select语句,称为嵌套查询,又称子查询。

sql 复制代码
SELECT  *  FROM   t1   WHERE  column1 =  ( SELECT  column1  FROM  t2 ... );

子查询外部的语句可以是insert / update / delete / select 的任何一个,最常见的是 select。

根据子查询的结果不同分为以下四种:

|-----------|--------------------------------------------------------------|
| 标量子查询 | 子查询结果为单个值 [一行一列],常用操作符:= <> > >= < <= |
| 列子查询 | 子查询结果为一列,但可以是多行,常用操作符:in / not in(在指定的集合范围内多选一 / 不在指定的集合范围内) |
| 行子查询 | 子查询结果为一行,但可以是多列,常用操作符:= 、<> 、IN 、NOT IN |
| 表子查询 | 子查询结果为多行多列[相当于子查询结果是一张表], |

子查询可书写的位置为:where之后、from之后、select之后。

**要点:**先对需求做拆分,明确具体的步骤,然后再逐条编写SQL语句。 最终将多条SQL语句合并为一条。

三、分页条件查询

1、使用PageHelper进行分页查询

①SQL语句查询

使用LIMIT关键字,格式为:limit 开始索引 每页显示的条数。

sql 复制代码
select * from emp  limit 0,10;
-- 查询第1-10条数据作为第一页

select * from emp  limit 10,10;
-- 查询第11-20条数据作为第二页

②封装页数和记录数

后台给前端返回的数据包含:List集合(数据列表)、total(总记录数)。而这两部分我们通常封装到PageResult对象中,并将该对象转换为json格式的数据响应回给浏览器。并定义对应的实体类用于条件查询

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult {
        private Long total; //总记录数
        private List rows; //当前页数据列表
}
java 复制代码
@Data
public class EmpQueryParam {
        private Integer page;
        private Integer pageSize;
        private String name;
        private Integer gender;
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private LocalDate begin;
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private LocalDate end;
}

③在maven中导入依赖

XML 复制代码
<!--分页插件PageHelper-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.7</version>
</dependency>

④Controller层

java 复制代码
    @GetMapping
    public Result page(EmpQueryParam empQueryParam)
    {
        log.info("查询员工信息,{}",empQueryParam);
      PageResult pageResult = empService.page(empQueryParam);
      return Result.success(pageResult);
    }

⑤在ServiceImpl中重写page方法

Service:

java 复制代码
    /**
     * 分页查询
     */
     PageResult page(EmpQueryParam empQueryParam);

ServiceImpl:

java 复制代码
@Override
public PageResult page(Integer page, Integer pageSize) {
    //1. 设置分页参数
    PageHelper.startPage(page,pageSize);

    //2. 执行查询
    List<Emp> empList = empMapper.list();
    Page<Emp> p = (Page<Emp>) empList;

    //3. 封装结果
    return new PageResult(p.getTotal(), p.getResult());
}

⑥编写Mapper层和对应的xml

java 复制代码
    /**
     * 分页查询员工信息
     */
    public List<Emp> list(EmpQueryParam empQueryParam);
XML 复制代码
    <select id="list" resultType="com.genshin.pojo.Emp">
        select e.*, d.name deptName from emp e left join dept d on e.dept_id = d.id
        <where>
            <if test="name != null and name != ''">
                e.name like concat('%',#{name},'%')
            </if>
            <if test="gender != null">
                and e.gender = #{gender}
            </if>
            <if test="begin != null and end != null">
                and e.entry_date between #{begin} and #{end}
            </if>
        </where>
        order by e.update_time desc
    </select>

**注意:**PageHelper实现分页查询时,SQL语句的结尾一定一定一定不要加分号(;).。PageHelper只会对紧跟在其后的第一条SQL语句进行分页处理。

相关推荐
大龄程序员狗哥5 小时前
第25篇:Q-Learning算法解析——强化学习中的经典“价值”学习(原理解析)
人工智能·学习·算法
南境十里·墨染春水5 小时前
linux学习进展 线程同步——互斥锁
java·linux·学习
nashane6 小时前
HarmonyOS 6学习:旋转动画优化与长截图性能调优——打造丝滑交互体验的深度实践
学习·交互·harmonyos·harmonyos 5
华清远见IT开放实验室7 小时前
智能手表完整项目实现,比赛求职双向加分,基于嵌入式大赛推荐开发板(STM32U5)
stm32·单片机·嵌入式硬件·学习·智能手表·嵌入式大赛
炽烈小老头7 小时前
【 每天学习一点算法 2026/04/22】四数相加 II
学习·算法
uncle_ll7 小时前
LangChain基础学习笔记
笔记·学习·langchain·llm·rag
三品吉他手会点灯7 小时前
C语言学习笔记 - 14.C编程预备计算机专业知识 - 本讲内容概述
c语言·笔记·学习
Thanwind7 小时前
从0开始的机器学习之旅(二):监督学习,从线性回归说起
学习·机器学习·线性回归
2501_942326447 小时前
易速乐考,轻松备考
学习·教育电商
菜鸟‍7 小时前
【CVPR 2026】LitePT:更轻、更强的点云 Transformer【论文学习】
深度学习·学习·transformer