后端学习:数据库MySQL学习

news2024/11/16 21:56:44

数据库简介

  数据库:英文为 DataBase,简称DB,它是存储和管理数据的仓库。
  接下来,我们来学习Mysql的数据模型,数据库是如何来存储和管理数据的。在介绍 Mysql的数据模型之前,需要先了解一个概念:关系型数据库。
  关系型数据库(RDBMS)是指建立在关系模型基础上,由多张相互连接的二维表组成的数据库。二维表,指的是由行和列组成的表。

二维表的优点:
	使用表存储数据,格式统一,便于维护
	使用SQL语言操作,标准统一,使用方便,可用于复杂查询

MySQL是关系型数据库,是基于二维表进行数据存储的,具体的结构图下:
在这里插入图片描述
  通过MySQL客户端连接数据库管理系统DBMS,然后通过DBMS操作数据库使用MySQL客户端,向数据库管理系统发送一条SQL语句,由数据库管理系统根据SQL语句指令去操作数据库中的表结构及数据。一个数据库服务器中可以创建多个数据库,一个数据库中也可以包含多张表,而一张表中又可以包含多行记录。

在Mysql数据库服务器当中存储数据,你需要:
	1. 先去创建数据库(可以创建多个数据库,之间是相互独立的)
	2. 在数据库下再去创建数据表(一个数据库下可以创建多张表)
	3. 再将数据存放在数据表中(一张表可以存储多行数据)

SQL通用语法

  SQL:一门操作关系型数据库的编程语言,定义操作所有关系型数据库的统一标准。
  SQL语句可以单行或多行书写,以分号结尾。

在这里插入图片描述

  SQL语句可以使用空格/缩进来增强语句的可读性。
在这里插入图片描述

  MySQL数据库的SQL语句不区分大小写。
在这里插入图片描述

  注释:
    1.单行注释:-注释内容或#注释内容(MySQL特有)
    2.多行注释:/* 注释内容 */

SQL数据类型

  MySQL中的数据类型有很多,主要分为三类:数值类型、字符串类型、日期时间类型。

数值类型

类型大小有符号(SIGNED)范围(默认)无符号(UNSIGNED)范围描述
TINYINT1byte(-128,127)(0,255)小整数值
SMALLINT2bytes(-32768,32767)(0,65535)大整数值
MEDIUMINT3bytes(-8388608,8388607)(0,16777215)大整数值
INT/INTEGER4bytes(-2147483648,2147483647)(0,4294967295)大整数值
BIGINT8bytes(-263, 263-1)(0,264-1)极大整数值
FLOAT4bytes(-3.402823466 E+38,3.402823466351 E+38)0 和 (1.175494351 E-38,3.402823466 E+38)单精度浮点数值
DOUBLE8bytes(-1.7976931348623157E+308,1.7976931348623157E+308)0 和(2.2250738585072014 E-308,1.7976931348623157E+308)双精度浮点数值
DECIMAL依赖于M(精度)和D(标度)的值依赖于M(精度)和D(标度)的值小数值(精确定点数)

字符串类型

类型大小描述
CHAR0-255 bytes定长字符串(需要指定长度)
VARCHAR0-65535 bytes变长字符串(需要指定长度)
TINYBLOB0-255 bytes不超过255个字符的二进制数据
TINYTEXT0-255 bytes短文本字符串
BLOB0-65 535 bytes二进制形式的长文本数据
TEXT0-65 535 bytes长文本数据
MEDIUMBLOB0-16 777 215 bytes二进制形式的中等长度文本数据
MEDIUMTEXT0-16 777 215 bytes中等长度文本数据
LONGBLOB0-4 294 967 295 bytes二进制形式的极大文本数据
LONGTEXT0-4 294 967 295 bytes极大文本数据

  char 与 varchar 都可以描述字符串,char是定长字符串,指定长度多长,就占用多少个字符,和字段值的长度无关 。而varchar是变长字符串,指定的长度为最大占用长度 。相对来说,char的性能会更高些。

日期时间类型

类型大小范围格式描述
DATE31000-01-01 至 9999-12-31YYYY-MM-DD日期值
TIME3-838:59:59 至 838:59:59HH:MM:SS时间值或持续时间
YEAR11901 至 2155YYYY年份值
DATETIME81000-01-01 00:00:00 至9999-12-31 23:59:59YYYY-MM-DD HH:MM:SS混合日期和时间值
TIMESTAMP41970-01-01 00:00:01 至2038-01-19 03:14:07YYYY-MM-DD HH:MM:SS混合日期和时间值,时间戳

SQL语句分类

  SQL语句根据其功能被分为四大类:DDL、DML、DQL、DCL

在这里插入图片描述

分类全称说明
DDLData Definition Language数据定义语言,用来定义数据库对象(数据库,表,字段)
DMLData Manipulation Language数据操作语言,用来对数据库表中的数据进行增删改
DOLData Query Language数据查询语言,用来查询数据库中表的记录
DCLData Control Language数据控制语言,用来创建数据库用户、控制数据库的访问权限

项目开发流程如下:
在这里插入图片描述

在上述的流程当中,针对于数据库来说,主要包括三个阶段:
	1. 数据库设计阶段:参照页面原型以及需求文档设计数据库表结构
	2. 数据库操作阶段:根据业务功能的实现,编写SQL语句对数据表中的数据进行增删改查操作
	3. 数据库优化阶段:通过数据库的优化来提高数据库的访问性能。
		优化手段:索引、SQL优化、分库分表等

数据库设计-DDL-数据库操作

  DDL英文全称是Data Definition Language(数据定义语言),用来定义数据库对象(数据库、表)。DDL中数据库的常见操作:查询、创建、使用、删除。

查询数据库

查询所有数据库:show databases;
在这里插入图片描述

查询当前数据库:select database();
要操作某一个数据库,必须要切换到对应的数据库中。通过指令:select database() ,就可以查询到当前所处的数据库。
在这里插入图片描述

创建数据库

创建数据库语法:create database if not exists 数据库名;
数据库不存在,则创建该数据库;如果存在则不创建。

使用数据库

要操作某一个数据库下的表时,就需要通过指令,切换到对应的数据库下,否则不能操作。
使用数据库语法:use 数据库名 ;

删除数据库

删除数据库语法:drop database if exists 数据库名;
数据库存在时删除

数据库设计-DDL-表操作

  约束:是指作用在表中字段上的规则,用于限制存储在表中的数据。来保证数据库当中数据的正确性、有效性和完整性。

  在MySQL数据库当中,提供了以下5种约束:

约束描述关键字
非空约束限制该字段值不能为nullnot null
唯一约束保证字段的所有数据都是唯一、不重复的unique
主键约束主键是一行数据的唯一标识,要求非空且唯primary key
默认约束保存数据时,如果未指定该字段值,则采用默认值default
外键约束让两张表的数据建立连接,保证数据的一致性和完整性foreign key

主键自增:auto_increment,每次插入新的行记录时,数据库自动生成id字段(主键)下的值具有auto_increment的数据列是一个正数序列开始增长(从1开始自增)。

创建表

在这里插入图片描述

注意: [ ] 中的内容为可选参数; 最后一个字段后面没有逗号

案例:创建tb_user表
在这里插入图片描述

建表语句:

create table tb_user (
	id int primary key comment 'ID,唯一标识',
	username varchar(20) not null unique comment '用户名',
	name varchar(10) not null comment '姓名',
	age int comment '年龄',
	gender char(1) default '男' comment '性别'
) comment '用户表';

查询表

查询当前数据库所有表:show tables;
查询表结构:desc 表名;
查询建表语句:show create table表名;

图形化界面:
在这里插入图片描述

修改表

添加字段:alter table 表名 add 字段名 类型(长度) [comment注释] [约束];
修改字段类型:alter table 表名 modify 字段名 新数据类型(长度);
修改字段名和字段类型:alter table 表名 change l旧字段名 新字段名 类型(长度) [comment注释] [约束];
删除字段:alter table 表名 drop column 字段名;
修改表名:rename table 表名 to 新表名;

图形化界面:添加字段

在这里插入图片描述

图形化界面:修改数据类型和字段名

在这里插入图片描述

图形化界面:删除字段

在这里插入图片描述

图形化界面:修改表名

在这里插入图片描述

删除表

删除表语法:drop table [ if exists ] 表名;

图形化操作:删除表
在这里插入图片描述

数据库操作-DML

  DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作。

添加数据(INSERT)

向指定字段添加数据:insert into 表名 (字段名1, 字段名2) values (值1, 值2);
全部字段添加数据:insert into 表名 values (值1, 值2, ...);
批量添加数据(指定字段):insert into 表名 (字段名1, 字段名2) values (值1, 值2), (值1, 值2);
批量添加数据(全部字段):insert into 表名 values (值1, 值2, ...), (值1, 值2, ...);

案例1:向tb_emp表的username、name、gender字段插入数据

-- 因为设计表时create_time, update_time两个字段不能为NULL,所以也做为要插入的字段
insert into tb_emp(username, name, gender, create_time, update_time) values ('wuji', '张无忌', 1, now(), now());

案例2:向tb_emp表的所有字段插入数据

insert into tb_emp values (null, 'zhirou', '123', '周芷若', 2, '1.jpg', 1, '2010-01-01',now(), now());

案例3:批量向tb_emp表的username、name、gender字段插入数据

insert into tb_emp(username, name, gender, create_time, update_time)
values ('weifuwang', '韦一笑', 1, now(), now()),('fengzi', '张三疯', 1, now(), now());

图形化操作:双击tb_emp表查看数据
在这里插入图片描述

Insert操作的注意事项:	
	1. 插入数据时,指定的字段顺序需要与值的顺序是一一对应的。
	2. 字符串和日期型数据应该包含在引号中。
	3. 插入的数据大小,应该在字段的规定范围内。

修改数据(UPDATE)

update语法:update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , .... [where 条件] ;

案例1:将tb_emp表中id为1的员工,姓名name字段更新为'张三'
update tb_emp set name='张三',update_time=now() where id=1;

注意事项:
	1. 修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据。
	2. 在修改数据时,一般需要同时修改公共字段update_time,将其修改为当前操作时间。

删除数据(DELETE)

delete语法:delete from 表名 [where 条件] ;

案例1:删除tb_emp表中id为1的员工
delete from tb_emp where id = 1;

注意事项:
	• DELETE 语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据。
	• DELETE 语句不能删除某一个字段的值(可以使用UPDATE,将该字段值置为NULL即可)。
	• 当进行删除全部数据操作时,会提示询问是否确认删除所有数据,直接点击Execute即可。

数据库查询操作-DQL

  DQL英文全称是Data Query Language(数据查询语言),用来查询数据库表中的记录。

  查询关键字:SELECT

  查询操作是所有SQL语句当中最为常见,也是最为重要的操作。在一个正常的业务系统中,查询操作的使用频次是要远高于增删改操作的。当打开某个网站或APP所看到的展示信息,都是通过从数据库中查询得到的,而在这个查询过程中,还会涉及到条件、排序、分页等操作。

  DQL查询语句,语法结构如下:
在这里插入图片描述

DQL语句-单表操作

基本查询

查询多个字段:select 字段1,字段2,字段3 from 表名;
查询所有字段(通配符):select*from表名;
设置别名:select字段1[as别名1],字段2[as别名2]from表名;
去除重复记录:select distinct字段列表from表名;

注:* 号代表查询所有字段,在实际开发中尽量少用(不直观、影响效率)
# 案例1:查询指定字段 name,entrydate并返回
select name,entrydate from tb_emp;

# 案例2:查询返回所有字段
select * from tb_emp;

# 案例3:查询所有员工的 name,entrydate,并起别名(姓名、入职日期)
select name as "姓名" , entrydate as "入职日期"  from tb_emp;

# 案例4:查询已有的员工关联了哪几种职位(不要重复)
select distinct job from tb_emp;

条件查询(where)

语法:select 字段列表 from 表名 where 条件列表 ; 
条件列表:意味着可以有多个条件

  学习条件查询就是学习条件的构建方式,而在SQL语句当中构造条件的运算符分为两类:比较运算符、逻辑运算符

比较运算符功能
>大于
>=大于等于
<小于
<=小于等于
=等于
<> 或 !=不等于
between … and …在某个范围之内(含最小、最大值)
in(…)在in之后的列表中的值,多选一
like 占位符模糊匹配(_匹配单个字符, %匹配任意个字符)
is null是null
逻辑运算符功能
and 或 &&并且 (多个条件同时成立)
or 或 1或者 (多个条件任意一个成立)
not 或 !非 , 不是
# 案例1:查询 姓名 为 杨逍 的员工
select * from tb_emp where name='杨逍' ;

# 案例2:查询 id小于等于5 的员工信息
select * from tb_emp where id<=5 ;

# 案例3:查询 没有分配职位 的员工信息
# 注意:查询为NULL的数据时,不能使用 = null
select * from tb_emp where job is null ;

# 案例4:查询 有职位 的员工信息
select * from tb_emp where job is not null ;

# 案例5:查询 密码不等于 '123456' 的员工信息
select * from tb_emp where password != 123456 ;

# 案例6:查询 入职日期 在 '2000-01-01' (包含) 到 '2010-01-01'(包含) 之间的员工信息
select * from tb_emp where entrydate>= '2000-01-01' and entrydate<= '2010-01-01';
select * from tb_emp where entrydate between '2000-01-01' and '2010-01-01';

# 案例7:查询 入职时间 在 '2000-01-01' (包含) 到 '2010-01-01'(包含) 之间 且 性别为女的员工信息
select * from tb_emp where entrydate between '2000-01-01' and '2010-01-01' and gender=2;

# 案例8:查询 职位是 2 (讲师), 3 (学工主管), 4 (教研主管) 的员工信息
select * from tb_emp where job=2 or job=3 or job=4;
select * from tb_emp where job in (2,3 ,4);

# 案例9:查询 姓名 为两个字的员工信息
# 通配符 "_" 代表任意1个字符
select * from tb_emp where name like '__';

# 案例10:查询 姓 '张' 的员工信息
# 通配符 "%" 代表任意个字符(0个 ~ 多个)
select * from tb_emp where name like '张%';

聚合函数

  之前做的查询都是横向查询,就是根据条件一行一行的进行判断,而使用聚合函数查询就是纵向查询,它是对一列的值进行计算,然后返回一个结果值。(将一列数据作为一个整体,进行纵向计算)

语法:select 聚合函数(字段列表) from 表名 ;
注意 : 聚合函数会忽略空值,对NULL值不作为统计。

常用聚合函数:

函数功能描述
count统计数量按照列去统计有多少行数据(在根据指定的列统计的时候,如果这一列中有null的行,该行不会被统计在其中)
max最大值计算指定列的最大值
min最小值计算指定列的最小值
avg平均值计算指定列的平均值
sum求和计算指定列的数值和,如果不是数值类型,那么计算结果为0
# 案例1:统计该企业员工数量
# count(字段)
select count(name) from tb_emp ;
select count(id) from tb_emp;

# count(常量)
select count(0) from tb_emp;
select count('A') from tb_emp;

# count(*) 推荐此写法(MySQL底层进行了优化)
select count(*) from tb_emp;


# 案例2:统计该企业最早入职的员工
select  min(entrydate) from tb_emp ;

# 案例3:统计该企业最迟入职的员工
select  max(entrydate) from tb_emp ;

# 案例4:统计该企业员工 ID 的平均值
select  avg(id) from tb_emp ;

# 案例5:统计该企业员工的 ID 之和
select  sum(id) from tb_emp ;

分组查询(group by)

  分组: 按照某一列或者某几列,把相同的数据进行合并输出。分组其实就是按列进行分类(指定列下相同的数据归为一类),然后可以对分类完的数据进行合并计算。分组查询通常会使用聚合函数进行计算。

语法:select 字段列表 from 表名 [where 条件] group by 分组字段名 [having 分组后过滤条件];

注意事项:
	• 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义
	• 执行顺序:where > 聚合函数 > having
	
where与having区别(面试题)
	执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
	判断条件不同:where不能对聚合函数进行判断,而having可以。
# 案例1:根据性别分组 , 统计男性和女性员工的数量
select gender,count(*) from tb_emp group by gender ;

# 案例2:查询入职时间在 '2015-01-01' (包含) 以前的员工 , 并对结果根据职位分组 , 获取员工数量大于等于2的职位
select job,count(*) from tb_emp
# 分组前:筛选出入职时间在'2015-01-01'之前的员工
where entrydate<='2015-01-01'

# 按照职位分组(ob字段下相同的数据划分为一组)
group by job

# 分组后:筛选出各组中员工数量>=2的(仅保留满足条件的组)
having count(*)>=2;

排序查询(order by)

  排序在日常开发中是非常常见的一个操作,有升序排序,也有降序排序。ASC :升序(默认值)、DESC:降序

语法:

select 字段列表
from 表名
[where 条件列表]
[group by 分组字段 ]
order by 字段1 排序方式1 , 字段2 排序方式2;
注意事项:如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序
# 案例1:根据入职时间, 对员工进行升序排序
# 默认就是ASC(升序)
select * from tb_emp order by entrydate ASC ;
select * from tb_emp order by entrydate;

# 案例2:根据入职时间,对员工进行降序排序
select * from tb_emp order by entrydate desc ;

# 案例3:根据入职时间对公司的员工进行升序排序,入职时间相同,再按照更新时间进行降序排序
select * from tb_emp order by entrydate  ,update_time desc ;

分页查询((limit)

  分页操作在业务系统开发时,也是非常常见的一个功能,日常我们在网站中看到的各种各样的分页条,后台也都需要借助于数据库的分页操作。

分页查询语法:select 字段列表 from 表名 limit 起始索引, 查询记录数 ;
# 案例1:从起始索引0开始查询员工数据, 每页展示5条记录
select * from tb_emp limit 0, 5 ;

# 案例2:查询 第1页 员工数据, 每页展示5条记录
# 如果查询的是第1页数据,起始索引可以省略,直接简写为:limit 条数
select * from tb_emp limit  5 ;

# 案例3:查询 第2页 员工数据, 每页展示5条记录
select * from tb_emp limit  5,5 ;

# 案例4:查询 第3页 员工数据, 每页展示5条记录
select * from tb_emp limit  10,5 ;
#员工性别统计:
-- if(条件表达式, true取值 , false取值)
select if(gender=1,'男性员工','女性员工') AS 性别, count(*) AS 人数
from tb_emp
group by gender;


# 员工职位统计:
# case 表达式 when 值1 then 结果1  when 值2  then 结果2 ...  else result end
select (case job
		when 1 then '班主任'
		when 2 then '讲师'
		when 3 then '学工主管'
		when 4 then '教研主管'
		else '未分配职位'
	end) AS 职位 ,
	count(*) AS 人数
from tb_emp
group by job;

DQL语句-多表操作

多表的设计

  关于单表的操作(单表的设计、单表的增删改查)已经学习完了。接下来就要来学习多表的操作,首先来学习多表的设计。项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:一对多(多对一)、多对多、一对一

一对多(多对一)

在这里插入图片描述

  一对多关系实现:在数据库表中多的一方,添加字段,来关联属于一这方的主键。使用外键约束,让两张表的数据建立连接,保证数据的一致性和完整性。
  对应的关键字:foreign key

外键约束的语法:
-- 创建表时指定
create table 表名(
	字段名 数据类型,
	...
	[constraint] [外键名称] foreign key (外键字段名) 	references
	主表 (主表列名)
);
-- 建完表后,添加外键
alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名);

方式1:通过SQL语句操作

-- 修改表: 添加外键约束
alter table tb_emp
add constraint  fk_dept_id foreign key (dept_id) references tb_dept(id);

方式2:图形化界面操作
在这里插入图片描述

物理外键:指使用foreign key定义外键关联另外一张表。
	缺点:
		影响增、删、改的效率(需要检查外键关系)。
		仅用于单节点数据库,不适用与分布式、集群场景。
		容易引发数据库的死锁问题,消耗性能。
	
逻辑外键:指在业务层逻辑中,解决外键关联。
	通过逻辑外键,就可以很方便的解决上述问题。
	在现在的企业开发中,很少会使用物理外键,都是使用逻辑外键。 
	甚至在一些数据库开发规范中,会明确指出禁止使用物理外键 foreign key
一对一

  一对一关系表在实际开发中应用起来比较简单,通常是用来做单表拆分,也就是将一张大表拆分成两张小表,将大表中的一些基础字段放在一张表当中,将其他的字段放在另外一张表当中,以此来提高数据的操作效率。
  一对一的应用场景: 用户表(基本信息+身份信息)
  其实,一对一我们可以看成一种特殊的一对多。同样,我们也可以通过外键来体现一对一之间的关系,只需要在任意一方来添加一个外键就可
以了。

一对一 :在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)

在这里插入图片描述

在这里插入图片描述

多对多

  多对多的关系在开发中属于也比较常见的。比如:学生和老师的关系,一个学生可以有多个授课老师,一个授课老师也可以有多个学生。在比如:学生和课程的关系,一个学生可以选修多门课程,一个课程也可以供多个学生选修。

案例:学生与课程的关系
关系:一个学生可以选修多门课程,一门课程也可以供多个学生选择
实现关系:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

在这里插入图片描述

多表查询

  多表查询:查询时从多张表中获取所需数据

单表查询的SQL语句:select 字段列表 from 表名;
多表查询的SQL语句:select 字段列表 from 表1, 表2;

直接使用会出现无效的笛卡尔积,需要给多表查询加上连接查询的条件。
多表查询的SQL语句:select * from 表1, 表2 where 连接条件 ;

如:select * from tb_emp , tb_dept where tb_emp.dept_id = tb_dept.id ;

  多表查询可以分为:连接查询(内连接, 外连接)子查询
  内连接:相当于查询A、B交集部分数据
在这里插入图片描述

  外连接:
    左外连接:查询 左表 所有数据(包括两张表交集部分数据)
    右外连接:查询 右表 所有数据(包括两张表交集部分数据)

连接查询
内连接

  内连接查询:查询两表或多表中交集部分数据。
  内连接从语法上可以分为:隐式内连接、显式内连接

隐式内连接:select 字段列表 from 表1 , 表2 where 条件 ... ;
显式内连接:select 字段列表 from 表1 [ inner ] join 表2 on 连接条件 ... ;

多表查询时给表起别名:
	tableA  as 别名1  ,  tableB  as 别名2 ;
	tableA 别名1  ,  tableB 别名2 ;
案例:查询员工的姓名及所属的部门名称
隐式内连接实现
select tb_emp.name , tb_dept.name -- 分别查询两张表中的数据
from tb_emp , tb_dept -- 关联两张表
where tb_emp.dept_id = tb_dept.id; -- 消除笛卡尔积

显式内连接实现
select tb_emp.name , tb_dept.name
from tb_emp inner join tb_dept
on tb_emp.dept_id = tb_dept.id;
外连接

  外连接分为两种:左外连接 和 右外连接。

左外连接语法结构:select 字段列表 from 表1 left [ outer ] join 表2 on 连接条件 ... ;
右外连接语法结构:select 字段列表 from 表1 right [ outer ] join 表2 on 连接条件 ... ;
案例:查询员工表中所有员工的姓名, 和对应的部门名称
-- 左外连接:以left join关键字左边的表为主表,查询主表中所有数据,以及和主表匹配的右边表中的数据
select emp.name , dept.name
from tb_emp AS emp left join tb_dept AS dept
on emp.dept_id = dept.id;

案例:查询部门表中所有部门的名称, 和对应的员工名称
-- 右外连接
select dept.name , emp.name
from tb_emp AS emp right join  tb_dept AS dept
on emp.dept_id = dept.id;
注意事项:左外连接和右外连接是可以相互替换的,只需要调整连接查询时SQL语句中表的先后顺序就可以了。
		  日常开发使用中,更偏向于左外连接。
		  没有匹配到的数据,填充为null
子查询

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

形式:select * from t1 where column1=(select column1 from t2 ……);
子查询外部的语句可以是 insert/update/delete/select 的任何一个,最常见的是select。
标量子查询(子查询结果为单个值[一行一列])

  子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。
常用的操作符: =、<>、>、>=、<、<=

案例1:查询"教研部"的所有员工信息
将需求分解为两步:1. 查询 "教研部" 部门ID、2. 根据 "教研部" 部门ID,查询员工信息

-- 1.查询"教研部"部门ID
select id from tb_dept where name = '教研部';

-- 2.根据"教研部"部门ID, 查询员工信息
select * from tb_emp where dept_id = 2;

-- 合并出上两条SQL语句
select * from tb_emp where dept_id = (select id from tb_dept where
name = '教研部');

案例2:查询在 "方东白" 入职之后的员工信息
将需求分解为两步:1. 查询 方东白 的入职日期、2. 查询 指定入职日期之后入职的员工信息

-- 1.查询"方东白"的入职日期
select entrydate from tb_emp where name = '方东白';

-- 2.查询指定入职日期之后入职的员工信息
select * from tb_emp where entrydate > '2012-11-01';

-- 合并以上两条SQL语句
select * from tb_emp where entrydate > (select entrydate from tb_emp where name = '方东白');
列子查询(子查询结果为一列,但可以是多行)

  常用的操作符:

操作符描述
IN在指定的集合范围之内,多选一
NOT IN不在指定的集合范围之内
案例:查询"教研部""咨询部"的所有员工信息
分解为两步:
	1. 查询 "销售部""市场部" 的部门ID
	2. 根据部门ID, 查询员工信息
	3. 
-- 1.查询"销售部"和"市场部"的部门ID
select id from tb_dept where name = '教研部' or name = '咨询部';

-- 2.根据部门ID, 查询员工信息
select * from tb_emp where dept_id in (3,2);

-- 合并以上两条SQL语句
select * from tb_emp where dept_id in (select id from tb_dept where name = '教研部' or name = '咨询部');

行子查询(子查询结果为一行,但可以是多列)

  常用的操作符:= 、<> 、IN 、NOT IN

案例:查询与"韦一笑"的入职日期及职位都相同的员工信息
拆解为两步进行:
	1. 查询 "韦一笑" 的入职日期 及 职位
	2. 查询与"韦一笑"的入职日期及职位相同的员工信息

-- 查询"韦一笑"的入职日期 及 职位
select entrydate , job from tb_emp where name = '韦一笑'; #查询结果:2007-01-01 , 2

-- 查询与"韦一笑"的入职日期及职位相同的员工信息
select * from tb_emp where (entrydate,job) = ('2007-01-01',2);

-- 合并以上两条SQL语句
select * from tb_emp where (entrydate,job) = (select entrydate , job from tb_emp where name = '韦一笑');
表子查询(子查询结果为多行多列[相当于子查询结果是一张表])

 &emsp:子查询返回的结果是多行多列,常作为临时表,这种子查询称为表子查询。

查询入职日期是 "2006-01-01" 之后的员工信息 , 及其部门信息
分解为两步执行:
	1. 查询入职日期是 "2006-01-01" 之后的员工信息
	2. 基于查询到的员工信息,在查询对应的部门信息
	
select * from emp where entrydate > '2006-01-01';
select e.*, d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id ;

事务

  在实际的业务开发中,有些业务操作要多次访问数据库。一个业务要发送多条SQL语句给数据库执行。需要将多次访问数据库的操作视为一个整体来执行,要么所有的SQL语句全部执行成功。如果其中有一条SQL语句失败,就进行事务的回滚,所有的SQL语句全部执行失败。
  简而言之:事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
  事务作用:保证在一个事务中多次操作数据库表中数据时,要么全都成功,要么全都失败。

MYSQL中有两种方式进行事务的操作:
	1. 自动提交事务:即执行一条sql语句提交一次事务。(默认MySQL的事务是自动提交)
	2. 手动提交事务:先开启,再提交

事务操作有关的SQL语句:

SQL语句描述
start transaction; / begin ;开启手动控制事务
commit;提交事务
rollback;回滚事务
手动提交事务使用步骤:
	第1种情况:开启事务  => 执行SQL语句   => 成功  => 提交事务
	第2种情况:开启事务  => 执行SQL语句   => 失败  => 回滚事务
--开启事务
start transaction

--删除部门
delete from tb dept where id =3;

--删除部门下的员工
delete from tb_emp where deptid =3;

--提交事务
commit;

回滚事务
rollback

索引

  索引是帮助数据库高效获取数据的数据结构 。简单来讲,就是使用索引可以提高查询的效率。

使用索引优点:
	1. 提高数据查询的效率,降低数据库的IO成本。
	2. 通过索引列对数据进行排序,降低数据排序的成本,降低CPU消耗。

使用索引缺点:
	1. 索引会占用存储空间。
	2. 索引大大提高了查询效率,同时却也降低了insert、update、delete的效率。

  MySQL数据库支持的索引结构有很多,如:Hash索引、B+Tree索引、Full-Text索引等。我们平常所说的索引,如果没有特别指明,都是指默认的 B+Tree 结构组织的索引。

创建索引:create [ unique ] index 索引名 on 表名 (字段名,... ) ;
案例:为tb_emp表的name字段建立一个索引
create index idx_emp_name on tb_emp(name);

在创建表时,如果添加了主键和唯一约束,就会默认创建:主键索引、唯一约束
查看索引:show index from 表名;
案例:查询 tb_emp 表的索引信息
show index from  tb_emp;
删除索引:drop index 索引名 on 表名;
案例:删除 tb_emp 表中name字段的索引
drop index idx_emp_name on tb_emp;

注意事项:
	主键字段,在建表时,会自动创建主键索引
	添加唯一约束时,数据库实际上会添加唯一索引

Mybatis

  在前面学习MySQL数据库时,都是利用图形化客户端工具(如:idea、datagrip),来操作数据库的。做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库,现在主流的方式是:Mybatis。

  MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。
  持久层:指的是数据访问层(dao),是用来操作数据库的。
  框架:是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上进行软件开发更加高效、规范、通用、可拓展。

Mybatis入门

Mybatis操作数据库的步骤:
	1. 准备工作(创建springboot工程、数据库表user、实体类User)
	2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
	3. 编写SQL语句(注解/XML)

创建springboot工程:
在这里插入图片描述
在这里插入图片描述
在数据库中创建表user
在这里插入图片描述

在Java程序中创建实体类User
在创建实体类User时,实体类的属性名与表中的字段名一一对应。
在这里插入图片描述

配置Mybatis

连接数据库的四大参数:
	MySQL驱动类
	登录名
	密码
	数据库连接字符串

  在springboot项目中,可以编写application.properties文件,配置数据库连接信息。要连接数据库,就需要配置数据库连接的基本信息,包括:driver-class-name、url 、username,password。

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234

编写SQL语句
  在创建出来的springboot工程中,在引导类所在包下,在创建一个包 mapper。在mapper包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫XxxMapper)。

在这里插入图片描述

@Mapper // 在运行时,会自动生成该接口的实现类对象,并且将该对象交给IOC容器管理
public interface UserMapper {
    //查询所有用户数据
    @Select("select id, name, age, gender, phone from user")
    public List<Userff> list();
}
@Mapper注解:表示是mybatis中的Mapper接口
程序运行时:框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理
@Select注解:代表的就是select查询,用于书写select查询语句

单元测试

  在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,并且在测试类上已经添加了注解 SpringBootTest,代表该测试类已经与SpringBoot整合。该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器)。我们要测试那个bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。
测试类代码如下:

@SpringBootTest
public class SpringbootMybatisQuickstartApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testList(){
        List<Userff> userList = userMapper.list();
        for (Userff user : userList) {
            System.out.println(user);
        }
    }
}

数据库连接池

  为了避免频繁的创建连接、销毁连接而带来的资源浪费,mybatis中使用了数据库连接池技术。

  数据库连接池是个容器,负责分配、管理数据库连接(Connection)。

数据库连接池的好处:
	1. 资源重用
	2. 提升系统响应速度
	3. 避免数据库连接遗漏

  官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)

获取连接: public Connection getConnection() throws SQLException;
第三方组织必须按照DataSource接口实现

常见的数据库连接池:C3P0、DBCP、Druid、Hikari (springboot默认)
现在使用更多的是:Hikari、Druid (性能更优越)

如果想把默认的数据库连接池切换为Druid数据库连接池:
1. 在pom.xml文件中引入依赖
	<dependency>
		<!-- Druid连接池依赖 -->
		<groupId>com.alibaba</groupId>
		<artifactId>druid-spring-boot-starter</artifactId>
		<version>1.2.8</version>
	</dependency>
	
2.  在application.properties中引入数据库连接配置
	方式1:
		spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
		spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
		spring.datasource.druid.username=root
		spring.datasource.druid.password=1234
		
	方式2:
		spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
		spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
		spring.datasource.username=root
		spring.datasource.password=1234

lombok

  Lombok是一个实用的Java类库,可以通过简单的注解来简化和消除一些必须有但显得很臃肿的Java代码。

在这里插入图片描述
  通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。

注解作用
@Getter/@Setter为所有的属性提供get/set方法
@ToString会给类自动生成易阅读的 toString 方法
@EqualsAndHashCode根据类所拥有的非静态字段自动重写 equals 方法和 hashCode方法
@Data提供了更综合的生成代码功能(@Getter + @Setter +@ToString + EqualsAndHashCode)
@NoArgsConstructor为实体类生成无参的构造器方法
@AllArgsConstructor为实体类生成除了static修饰的字段之外带有各参数的构造器方法。

lombok依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

Mybatis基础操作

删除

@Mapper
public interface EmpMapper {
    //  根据id删除数据,占位符-动态删除
    @Delete("delete from emp where id=#{id}")
    public void delete(Integer id);
}

  如果mapper接口方法形参只有一个普通类型的参数,#{…} 里面的属性名可以随便写,如:#{id}、#{value}。但是建议保持名字一致。

日志输入

  在Mybatis当中可以借助日志,查看到sql语句的执行、执行传递的参数以及执行结果。

具体操作如下:
	1. 打开application.properties文件
	2. 开启mybatis的日志,并指定输出到控制台
#指定mybatis输出日志的位置, 输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

  开启日志之后,我们再次运行单元测试,可以看到在控制台中,输出了以下的SQL语句信息:
在这里插入图片描述

  我们发现输出的SQL语句:delete from emp where id = ?,输入的参数16并没有在后面拼接,id的值是使用?进行占位。那这种SQL语句我们称为预编译SQL。预编译SQL有两个优势:1. 性能更高、2. 更安全(防止SQL注入)

性能更高:预编译SQL,编译一次之后会将编译后的SQL语句缓存起来,后面再次执行这条语句时,不会再次编译。(只是输入的参数不同)
更安全(防止SQL注入):将敏感字进行转义,保障SQL的安全性。
SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

参数占位符

  在Mybatis中提供的参数占位符有两种:${…} 、#{…}

#{...}
	执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值
	使用时机:参数传递,都使用#{…}

${...}
	拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题
	使用时机:如果对表名、列表进行动态设置时使用
	
注意事项:在项目开发中,建议使用#{...},生成预编译SQL,防止SQL注入安全。

新增

SQL语句:
insert into emp(username, name, gender, image, job, entrydate,
dept_id, create_time, update_time) values ('songyuanqiao','宋远桥',
1,'1.jpg',2,'2012-10-09',2,'2022-10-01 10:00:00','2022-10-01 10:00:00');
接口方法:
@Mapper
public interface EmpMapper {
	@Insert("insert into emp(username, name, gender, image, job,
	entrydate, dept_id, create_time, update_time) values (#{username}, #
	{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #
	{createTime}, #{updateTime})")
	public void insert(Emp emp);

说明:#{...} 里面写的名称是对象的属性名
测试类:
@SpringBootTest
class SpringbootMybatisBasicApplicationTests {
    // 创建对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testInsert() {
        //创建员工对象
        Emp emp = new Emp();
        emp.setUsername("tom");
        emp.setName("汤姆");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        empMapper.insert(emp);
    }

}

主键返回:在数据添加成功后,需要获取插入数据库数据的主键。

  默认情况下,执行插入操作时,是不会主键值返回的。如果我们想要拿到主键值,需要在Mapper接口中的方法上添加一个Options注解,并在注解中指定属性useGeneratedKeys=true和keyProperty=“实体类属性名”

主键返回代码实现:

// 新增员工,参数多-封装成一个对象
    //会自动将生成的主键值,赋值给emp对象的id属性
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into emp(username, name, gender, image, job,entrydate, dept_id, create_time, update_time) values" +
            " (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);

测试:

@SpringBootTest
class SpringbootMybatisBasicApplicationTests {
    // 创建对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testInsert() {
        //创建员工对象
        Emp emp = new Emp();
        emp.setUsername("tom2");
        emp.setName("汤姆2");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);

        empMapper.insert(emp);

        System.out.println(emp.getDeptId());
    }

}

更新

SQL语句:
update emp set username = 'linghushaoxia', name = '令狐少侠', gender =1 , 
image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2,
update_time = '2022-10-01 12:12:12' where id = 18;

接口方法:

/**
 * 根据id修改员工信息
 */
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}," +
        "entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);

测试类:

@SpringBootTest
class SpringbootMybatisBasicApplicationTests {
    // 创建对象
    @Autowired
    private EmpMapper empMapper;

    @Test
    public void testUpdate() {
        //要修改的员工信息
        Emp emp = new Emp();
        emp.setId(20);
        emp.setUsername("songdaxia");
        emp.setPassword(null);
        emp.setName("老宋");
        emp.setImage("2.jpg");
        emp.setGender((short)1);
        emp.setJob((short)2);
        emp.setEntrydate(LocalDate.of(2012,1,1));
        emp.setCreateTime(null);
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(2);

        //调用方法,修改员工数据
        empMapper.update(emp);

    }

}

查询

SQL语句:

select id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time from emp;

接口方法:

@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);

测试类:

@Test
public void testGetById(){
    Emp emp = empMapper.getById(1);
    System.out.println(emp);
}

数据封装
  我们看到查询返回的结果中大部分字段是有值的,但是deptId,createTime,updateTime这几个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?
在这里插入图片描述

原因如下:
	实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
	如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
	
解决方案:	
	1. 起别名
	2. 结果映射
	3. 开启驼峰命名

起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样

@Select("select id, username, password, name, gender, image, job, entrydate, " +
            "dept_id AS deptId, create_time AS createTime, update_time AS updateTime " +
            "from emp " +"where id=#{id}")
public Emp getById(Integer id);

手动结果映射:通过 @Results及@Result 进行手动结果映射

@Results({@Result(column = "dept_id", property = "deptId"),
          @Result(column = "create_time", property = "createTime"),
          @Result(column = "update_time", property = "updateTime")})
@Select("select id, username, password, name, gender, image, job,entrydate, " +
        "dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);

开启驼峰命名(推荐):如果字段名与属性名符合驼峰命名规则,mybatis会自动通过驼峰命名规则映射

# 在application.properties中添加:
mybatis.configuration.map-underscore-to-camel-case=true

要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。

条件查询

SQL语句:
select id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time
from emp
where name like '%张%'
and gender = 1
and entrydate between '2010-01-01' and '2020-01-01 '
order by update_time desc;

接口方法:

方式一
@Mapper
public interface EmpMapper {
@Select("select * from emp " +
		"where name like '%${name}%' " +
		"and gender = #{gender} " +
		"and entrydate between #{begin} and #{end} " +
		"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin,LocalDate end);
}


方式二(解决SQL注入风险)
使用MySQL提供的字符串拼接函数:concat('%' , '关键字' , '%')
@Mapper
public interface EmpMapper {
@Select("select * from emp " +
		"where name like concat('%',#{name},'%') " +
		"and gender = #{gender} " +
		"and entrydate between #{begin} and #{end} " +
		"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDatebegin, LocalDate end);
}

Mybatis的XML配置文件

  Mybatis的开发有两种方式:1. 注解、2. XML
  使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。

在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:
	1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下		(同包同名)
	2. XML映射文件的namespace属性为Mapper接口全限定名一致
	3. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。

<select> 标签:就是用于编写select查询语句的。
resultType 属性,指的是查询返回的单条记录所封装的类型。

在这里插入图片描述

XML配置文件实现
第1步:创建XML映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.EmpMapper">
    <!--查询操作-->
    <select id="list" resultType="com.example.pojo.Emp">
        select * from emp where name like concat('%',#{name},'%') and gender = #{gender}
        and entrydate between #{begin} and #{end} order by update_time desc
    </select>

</mapper>

Mybatis动态SQL

  在页面原型中,列表上方的条件是动态的,是可以不传递的,也可以只传递其中的1个或者2个或者全部。SQL语句会随着用户的输入或外部条件的变化而变化,我们称为:动态SQL。

动态SQL-if

<if> :用于判断条件是否成立。

<if test="条件表达式">
	要拼接的sql语句
</if>

<where>
	where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
	
<set>动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)

条件查询
示例:把SQL语句改造为动态SQL方式

原有的SQL语句:
<select id="list" resultType="com.itheima.pojo.Emp">
	select * from emp
	where name like concat('%',#{name},'%')
		and gender = #{gender}
		and entrydate between #{begin} and #{end}
	order by update_time desc
</select>

动态SQL语句:
<select id="list" resultType="com.itheima.pojo.Emp">
	select * from emp
	<where>
		<if test="name != null">
			name like concat('%',#{name},'%')
		</if>
		
		<if test="gender != null">
			and gender = #{gender}
		</if>
		
		<if test="begin != null and end != null">
			and entrydate between #{begin} and #{end}
		</if>
	</where>
	order by update_time desc
</select>

<!--更新操作-->
<update id="update">
update emp
<!-- 使用set标签,代替update语句中的set关键字 -->
<set>
	<if test="username != null">
		username=#{username},
	</if>
	
	<if test="name != null">
		name=#{name},
	</if>
	
	<if test="gender != null">
		gender=#{gender},
	</if>
	
	<if test="image != null">
		image=#{image},
	</if>
	
	<if test="job != null">
		job=#{job},
	</if>
	
	<if test="entrydate != null">
		entrydate=#{entrydate},
	</if>
	
	<if test="deptId != null">
		dept_id=#{deptId},
	</if>
	
	<if test="updateTime != null">
		update_time=#{updateTime}
	</if>
	
	</set>
	where id=#{id}
</update>

动态SQL-foreach

应用场景:删除功能(既支持删除单条记录,又支持批量删除)

使用 <foreach> 遍历指定方法中传递的参数集合
<foreach collection="" item="" separator="" open="" close=""> </foreach>

collection:遍历的集合
item:遍历出来的元素
separator:分隔符
open:遍历开始前拼接的SQL片段
close:遍历结束后拼接的SQ工片段
<!--批量删除操作-->
<delete id="deleteByIds">
	delete from emp where id in
	<foreach collection="ids" item="id" separator="," open="("	close=")">
		#{id}
	</foreach>
</delete>

动态SQL-sql、include

  在xml映射文件中配置的SQL,有时可能会存在很多重复的片段,此时就会存在很多冗余的代码。可以对重复的代码片段进行抽取,将其通过 标签封装到一个SQL片段,然后再通过 < include > 标签进行引用。

<sql> :定义可重用的SQL片段
<include> :通过属性refid,指定包含的SQL片段

SQL片段: 抽取重复的代码

<sql id="commonSelect">
	select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
通过 <include> 标签在原来抽取的地方进行引用
<select id="list" resultType="com.itheima.pojo.Emp">
	<include refid="commonSelect"/>
	<where>
		<if test="name != null">
			name like concat('%',#{name},'%')
		</if>
		
		<if test="gender != null">
			and gender = #{gender}
		</if>
		
		<if test="begin != null and end != null">
			and entrydate between #{begin} and #{end}
		</if>
		
	</where>
	order by update_time desc
</select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1415115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLO自制数据集及训练

使用 Make Sense 网站进行标注 https://www.makesense.ai/可以让AI帮你先标一下 一定要点一下 + ,不然不会加进去 导出标签

混淆矩阵、准确率、查准率、查全率、DSC、IoU、敏感度的计算

1.背景介绍 在训练的模型的时候&#xff0c;需要评价模型的好坏&#xff0c;就涉及到混淆矩阵、准确率、查准率、查全率、DSC、IoU、敏感度的计算。 2、混淆矩阵的概念 所谓的混淆矩阵如下表所示&#xff1a; TP:真正类&#xff0c;真的正例被预测为正例 FN:假负类&#xf…

OSI七层模型 | TCP/IP模型 | 网络和操作系统的联系 | 网络通信的宏观流程

文章目录 1.OSI七层模型2.TCP/IP五层(或四层)模型3.网络通信的宏观流程3.1.同网段通信3.2.跨网段通信 1.OSI七层模型 在计算机通信诞生之初&#xff0c;不同的厂商都生产自己的设备&#xff0c;都有自己的网络通讯标准&#xff0c;导致了不同厂家之间各种协议不兼容&#xff0…

Linux文本三剑客---grep

grep&#xff08;从文本或字符串种过滤特定内容。&#xff09; 格式&#xff1a;Usage: grep [OPTION]... PATTERNS [FILE]... 常用选项&#xff1a; -E 等价于 egrep 扩展正则 -i 忽略大小写 -w 匹配单词 -o 仅显示匹配内容 -r 递归匹配 -c 统计匹配的行数 -v 取反 -n 行号 -A…

ABAP 状态栏排除某些按钮

ABAP 状态栏排除某些按钮 GUI State状态栏 在状态栏这里有这些按钮&#xff0c;现在在导出界面要排除掉这些按钮&#xff1a; 将要排除的按钮追加到gt_code内表&#xff1a; gt_fcode功能码内表的定义 DATA:gt_fcode TYPE TABLE OF sy-ucomm,完整程序 *&---------…

SpringBoot不同的@Mapping使用

文章目录 一、介绍二、使用 一、介绍 一般Mapping类注解在Spring框架中用于将HTTP请求映射到对应的处理器方法。它们各自对应于不同类型的HTTP方法&#xff0c;主要用于RESTful Web服务中。以下是每个注解的作用&#xff1a; GetMapping: 用于映射HTTP GET请求到处理器方法。通…

Android读写文件,适配Q以上

Android Q升级了文件系统&#xff0c;访问文件不仅仅是说动态权限了&#xff0c;有各种限制。权限什么的就不赘述了&#xff0c;下面介绍一下在10以上的系统中访问文件。 首先是打开文件管理器 /*** 打开文件管理器 存储卡和外接U盘都可以访问*/public void openFileManager()…

【揭秘】ForkJoinTask全面解析

内容摘要 ForkJoinTask的显著优点在于其高效的并行处理能力&#xff0c;它能够将复杂任务拆分成多个子任务&#xff0c;并利用多核处理器同时执行&#xff0c;从而显著提升计算性能&#xff0c;此外&#xff0c;ForkJoinTask还提供了简洁的API和强大的任务管理机制&#xff0c…

Blender教程-编辑模式点线面的选择-06

一、新建立方体 ShiftA新建立方体用于演示 二、模式切换 按TAB键切换为编辑模式 点模式 在点模式下可以选择中物体的顶点。 线模式&#xff08;边模式&#xff09; 面模式 在熟悉编辑模式下的点线面基础操作以后&#xff0c;我们后续建模会以此为基础教程。

D. Epic Transformation(堆+贪心)

思路&#xff1a;我们删的策略是从次数多的数开始删&#xff0c;每次取两种不同的数&#xff0c;每种删去一个&#xff0c;然后放回堆中。 代码&#xff1a; void solve(){int n;cin >> n;map<int,int>mp;for(int i 1;i < n;i ){int x;cin >> x;mp[x] …

CAD-autolisp(二)——选择集、命令行设置对话框、符号表

目录 一、选择集1.1 选择集的创建1.2 选择集的编辑1.3 操作选择集 二、命令行设置对话框2.1 设置图层2.2 加载线型2.3 设置字体样式2.4 设置标注样式&#xff08;了解即可&#xff09; 三、符号表3.1 简介3.2 符号表查找3.2 符号表删改增 一、选择集 定义&#xff1a;批量选择…

ubuntu 20.04 更新 autoconf 版本

前言 由于最近打算交叉编译 python&#xff0c;依赖 libffi 库&#xff0c;而交叉编译 libffi 库&#xff0c;由于使用的是 github 上的 libffi&#xff0c;又提示 autoconf 版本太低了&#xff0c;所以&#xff0c;先更新 autoconf 的版本 当前 ubuntu 20.04 上安装的 autuco…

【数据分享】2015年泛第三极65国1km分辨率土壤侵蚀强度数据集(免费获取)

土壤数据是在环境、农业、生态等相关研究中都非常常用的数据&#xff01;我们之前发表过一篇介绍土壤数据来源的文章&#xff08;可查看之前推送的文章获悉详情&#xff09;&#xff01; 土壤侵蚀强度是土壤的重要属性&#xff01;本次我们给大家带来的是2015年泛第三极65国1k…

《合成孔径雷达成像算法与实现》Figure5.19

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

8.15合并区间(LC56)

算法&#xff1a; 和452. 用最少数量的箭引爆气球 (opens new window)和 435. 无重叠区间 (opens new window)都是一个套路。 这几道题都是判断区间重叠&#xff0c;区别就是判断区间重叠后的逻辑&#xff0c;本题是判断区间重贴后要进行区间合并。 步骤&#xff1a; 先排序…

自动化脚本不稳定,原来是软件弹窗惹的祸,2个方法解决!

很多同学在学习 App 自动化或者在项目中落地实践 App 自动化时&#xff0c;会发现编写的自动化脚本无缘无故的执行失败、不稳定。 而导致其问题很大原因是因为应用的各种弹窗&#xff08;升级弹窗、使用过程提示弹窗、评价弹窗等等&#xff09;&#xff0c;比如这样的&#xff…

nodejs下载 安装 配置环境

目录 1.下载 2、配置环境 1.下载 下载地址&#xff1a;https://nodejs.org/en/download/ 下载完成后&#xff0c;双击安装包&#xff0c;开始安装&#xff0c;一直点next即可。我把安装路径设置为 D:\Program Files\nodejs\ 安装完之后打开终端 windowR cmd 回车&#xff1…

C++:组合、继承与多态

面向对象设计的重要目的之一就是代码重用&#xff0c;这也是C的重要特性之一。代码重用鼓励人们使用已有的&#xff0c;得到认可并经过测试的高质量代码。多态允许以常规方式书写代码来访问多种现有的且已专门化了的相关类。继承和多态是面向对象程序设计方法的两个最主要的特性…

fix bug: FileNotFoundError: [Errno 2] No such file or directory: ‘nvcc‘

1.问题描述 运行的代码设计pycuda,会调用nvcc&#xff0c;确定已经安装cuda toolkit&#xff0c;在terminal中云运行 nvcc -V 能得到想到的结果&#xff1a; 但是在 pycharm中运行代码时提示&#xff1a; FileNotFoundError: [Errno 2] No such file or directory: nvcc 2.…

细数语音识别中的几个former

随着Transformer在人工智能领域掀起了一轮技术革命&#xff0c;越来越多的领域开始使用基于Transformer的网络结构。目前在语音识别领域中&#xff0c;Tranformer已经取代了传统ASR建模方式。近几年关于ASR的研究工作很多都是基于Transformer的改进&#xff0c;本文将介绍其中应…