《从零开始的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语句进行分页处理。

相关推荐
今天你TLE了吗1 小时前
JVM学习笔记:第九章——StringTable字符串常量池
java·jvm·笔记·后端·学习
Amazing_Cacao2 小时前
品鉴师高级|全局判断成体系(精品可可,精品巧克力)
笔记·学习
西野.xuan2 小时前
【effective c++】条款四十三:学习处理模版化基类内的名称
java·c++·学习
Shining05962 小时前
前沿模型系列(一)《大模型学习方法》
学习·其他·学习方法·infinitensor
Accerlator2 小时前
MySQL 学习
学习
星幻元宇VR2 小时前
VR应急救护学习机|让急救教育更直观
学习·安全·vr·虚拟现实
babe小鑫2 小时前
2026高职大数据技术专业学习数据分析的指南
大数据·学习·数据分析
.小小陈.2 小时前
C++进阶7:深入理解哈希表,从原理到 C++ 实践
开发语言·c++·学习·哈希算法
科技林总2 小时前
【系统分析师】11.1 软件需求
学习