Python测开28期-偕行-数据与SQL语法

一、数据库的基本概念

1、数据库简介

  • 数据库(DataBase) 就是一个以某种有组织的方式存储的数据集合
  • 是存储和管理数据的仓库
  • 其本质是一个文件系统
  • 数据库管理系统(DBMS)是一款管理软件

2、数据库分类

  • 关系型数据库(RDB: Relationship DataBase),也叫SQL数据库,采用了关系模型来组织数据的数据库。简单来说,关系模式就是二维表格模型。

    • MySQL(开源)

    • Oracle(商用)

    • Postgres(开源)

    • SQLite(开源,嵌入式数据库,Android默认数据库)

    • SQLServer(跨平台性不好)

    • 优点:

      • (1)容易理解,二维表的结构非常贴近现实世界,二维表格,容易理解。
      • (2)使用方便,通用的sql语句使得操作关系型数据库非常方便。
      • (3)易于维护,数据库的ACID属性,大大降低了数据冗余和数据不一致的概率。
      • (4)事务的一致性,关系型数据库的最大优点就是事务的一致性,这个特性,使得关系型数据库中可以适用于一切要求一致性比较高的系统中。比如:银行系统。
    • 瓶颈:

      • (1 )海量数据的读写效率:对于网站的并发量高,往往达到每秒上万次的请求,对于传统关系型数据库来说,硬盘I/o是一个很大的挑战。
      • (2) 高扩展性和可用性:在基于web的结构中,数据库是最难以横向拓展的,当一个应用系统的用户量和访问量与日俱增的时候,数据库没有办法像web Server那样简单的通过添加更多的硬件和服务节点来拓展性能和负载能力。
  • 非关系型数据库(NoSQL),not only SQL:主要指那些非关系型的、分布式的,且一般不保证ACID的数据存储系统;

    • MongoDB(开源,分布式文件存储的数据库)
    • Redis(开源,数据结构服务器, key-value 存储系统)
    • HBase(开源, 分布式面向列的数据库)
    • Neo4j(开源,图数据库)
    • 缺点:由于Nosql约束少,所以也不能够像sql那样提供where字段属性的查询。因此适合存储较为简单的数据。有一些不能够持久化数据,所以需要和关系型数据库结合。
  • NewSQL:各种新的可扩展/高性能数据库的简称, 这类数据库不仅具有NoSQL对海量数据的存储管理能力,还保持了传统数据库支持ACIDSQL等特性。

    • Vitess(开源):Vitess 是一个分布式 MySQL 工具集,它可以自动分片存储 MySQL 数据表,将单个 SQL 查询改写为分布式发送到多个 MySQL Server 上,支持行缓存(比 MySQL 本身缓存效率高)与复制容错等。Vitess 4.0 中有许多改进,可以使新用户更容易使用,可以很容易的在k8s上部署Vitess,从单一的 MySQL 或 MariaDB 迁移到Vitess 成为可能,而应用对此有所感知。

    • CockroachDB(免费):CockroachDB (蟑螂数据库)是一个可伸缩的、支持地理位置处理、支持事务处理的数据存储系统。CockroachDB 提供两种不同的的事务特性,包括快照隔离(snapshot isolation,简称SI)和顺序的快照隔离(SSI)语义,后者是默认的隔离级别。

3、使用场景

  • 关系型数据库

    • 需要做复杂处理的数据;
    • 数据量不是特别大的数据;
    • 对安全性能要求高的数据;
    • 数据格式单一的数据;
  • 非关系型数据库(NoSQL)

    • 数据模型比较简单
    • 需要灵活性更强的 IT 系统
    • 对数据库性能要求较高
    • 不需要高度的数据一致性

4、关系型数据库与非关系数据库对比

1.存储上

Sql通常以数据库表的形式存储,例如存储用户信息,SQL中增加外部关系的话,需要在原表中增加一个外键,来关联外部数据表。

NoSql采用key-value的形式存储。

2.事务

SQL中如果多张表需要同批次被更新,即如果其中一张表跟新失败的话,其他表也不会更新成功。这种场景可以通过事务来控制,可以在所有命令完成之后,再统一提交事务。在Nosql中没有事务这个概念,每一个数据集都是原子级别的。

3.数据表 VS 数据集

关系型是表格型的,存储在数据表的行和列中。彼此关联,容易提取。而非关系型是大块存储在一起。

4.预定义结构 VS 动态结构

在sql中,必须定义好字段和表结构之后,才能够添加数据,例如定义表的主键、索引、外键等。表结构可以在定义之后更新,但是如果有比较大的结构变更,就会变的比较复杂。

在Nosql数据库中,数据可以在任何时候任何地方添加。不需要预先定义。

5.存储规范 VS 存储代码

关系型数据库为了规范性,把数据分配成为最小的逻辑表来存储避免重复,获得精简的空间利用。但是多个表之间的关系限制,多表管理就有点复杂。

当然精简的存储可以节约宝贵的数据存储,但是现在随着社会的发展,磁盘上付出的代价是微不足知道的。

非关系型是平面数据集合中,数据经常可以重复,单个数据库很少被分开,而是存储成为一个整体,这种整块读取数据效率更高。

6.纵向拓展 VS 横向拓展

为了支持更多的并发量,SQL数据采用纵向扩展,提高处理能力,通过提高计算机性能来提高处理能力。

NoSql通过横向拓展,非关系型数据库天然是分布式的,所以可以通过集群来实现负载均衡。

二、MySQL的数据类型

  • 数字类型
  • 字符串类型
  • 日期和时间类型

1、数字类型

数据类型 说明
TINTINT 0~255 或 -128~127,1字节,最小的整数
SMALLINT 0~65535 或 -32768~32767,2字节,小型整数
MEDIUMINT 0~16777215 或 -8388608~8388607,3字节,中型整数
INT 0~4294967295 或 -2147683648~2147683647,4字节,标准整数
BIGINT 8字节,大整数
FLOAT 单精度浮点值
DOUBLE 双精度浮点值
BOOLEAN 布尔值

2、字符串类型

数据类型 说明
CHAR 1~255 个字符,固定长度字符串
VARCHAR 长度可变,最多不超过 255 个字符
TEXT 最大长度为 64K 的变长文本
TINYTEXT 与 TEXT 相同,但最大长度为 255 字节
MEDIUMTEXT 与 TEXT 相同,但最大长度为 16K
LONGTEXT 与 TEXT 相同,但最大长度为 4GB

3、日期和时间类型

数据类型 说明
DATE 日期,格式 YYYY-MM-DD
TIME 时间,格式 HH:MM:SS
DATETIME 日期和时间,格式 YYYY-MM-DD HH:MM:SS
TIMESTAMP 时间标签,功能和 DATETIME 相同,但范围较小
YEAR 年份可指定两位数字和四位数字的格式

三、SQL

1、简介

  • 结构化查询语言(Structured Query Language)简称 SQL;
  • 一种特殊目的的编程语言;
  • 一种数据库查询和程序设计语言;
  • 用于存取数据以及查询、更新和管理关系数据库系统;

通用语法

  • 可以单行或者多行书写,以分号结尾 ;
  • 可以使用空格和缩进来增加语句的可读性
  • 不区分大小写,一般关键字大写,数据库名 表名列名小写
  • 注释方式:
1、#:单行注释,MySQL 特有的单行注释
# select * from student_new

2、-- 单行注释
-- select * from student_new

3、多行注释
/*
select * from student_new
*/

SQL分类

  • 数据定义语言(DDL-Data definition language):用来定义数据库对象,比如数据库,表,列等;
  • 数据操作语言(DML-Data manipulation language):用来对数据库中表的记录进行更新;
  • 数据查询语言(DQL-Data query language):用来查询数据库中表的记录;
  • 数据控制语言(DCL-Data control language):用来定义数据库的访问权限和安全级别及创建用户;
操作 语法
库操作
创建数据库 CREATE {DATABASE / SCHEMA} [IF NOT EXISTS] 数据库名 CHARACTER SET [=] 字符集;
查看所有数据库 SHOW DATABASES;
切换当前使用数据库 USE 数据库名;
查看数据库的定义信息 SHOW CREATE DATABASE 数据库名;
修改数据库相关参数 ALTER {DATABASE} [数据库名] CHARACTER SET [=] 字符集;
删除数据库 DROP DATABASE [IF EXISTS] 数据库名;
表操作
创建表 CREATE TABLE <表名> ( <列名1> <列类型1>, <列名2> <列类型2>,<列名3> <列类型3>,PRIMARY KEY (<列名1>),FOREIGN KEY (<列名2>) REFERENCES <表名2>(<列名2>) );
列属性 列名 数据类型 [NOT NULL /NULL] [DEFAULT 默认值] [AUTO_INCREMENT] [PRIMARY KEY ] [ FOREIGN KEY ] [注释];
复制表 CREATE TABLE 数据表名 LIKE 源数据表名;
查看当前库中所有的表名 SHOW TABLES;
查看表结构 DESCRIBE 数据表名;
查看列结构 DESCRIBE 数据表名 列名;
添加新列 ALTER TABLE 表名 ADD 列名 列属性;
修改列定义 ALTER TABLE 表名 MODIFY 列名 列属性;
修改列名 ALTER TABLE 表名 CHANGE 旧列名 新列名 类型;
删除列 ALTER TABLE 表名 DROP 列名;
修改表名 ALTER TABLE 旧表名 RENAME AS 新表名;
删除表 DROP TABLE [IF EXISTS] 数据表名;
数据操作
插入数据 INSERT INTO 数据表名 (列名1, 列名2…) VALUES (值1, 值2…);
修改数据 UPDATE 数据表名 SET 列名1=值1 [, 列名2=值2…] [WHERE 条件表达式];
删除指定行 数据 DELETE FROM 数据表名 WHERE 条件表达式;
删除全部 数据 TRUNCATE TABLE 数据表名;

2、数据库操作

(1)创建数据库

  • 语法:CREATE {DATABASE|SCHEMA} [IF NOT EXISTS] 数据库名 CHARACTER SET [=] 字符集;
    • IF NOT EXISTS:可选项,创建前先判断,未存在时才执行创建语句;
    • 数据库名:必须指定的;
    • CHARACTER SET =字符集:可选项,用于指定数据库的字符集;
-- 创建数据库
create database if not exists goods character set = 'utf8mb4';

注意事项:

  • 不能与其他数据库重名
  • 名称可以由任意字母、阿拉伯数字、下划线(_)和“$”组成,但不能使用单独的数字
  • 名称最长可为 64 个字符,别名最长为 256 个字符。
  • 不能使用 MySQL 关键字作为数据库名
  • 建议采用小写来定义数据库名

(2)查看数据库

A、查看所有数据库

  • 语法:SHOW DATABASES;
    • DATABASES:必选项,用于列出当前用户权限范围内所能查看到的所有数据库名称
-- 查看所有数据库
show databases;

B、切换当前使用数据库

  • 语法:USE 数据库名;
-- 切换当前数据库
use litemall;

C、 查看数据库的定义信息

  • 语法:SHOW CREATE DATABASE 数据库名;
-- 查看数据库定义信息
show create database goods;

-- 结果:
-- CREATE DATABASE `goods` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */

(3)修改数据库相关参数

  • 语法:ALTER {DATABASE} [数据库名] CHARACTER SET [=] 字符集;
    • DATABASE:必选项
    • 数据库名:可选项,如果不指定要修改的数据库,那么将表示修改当前(默认)的数据库
    • CHARACTER SET = 字符集:可选项,用于指定数据库的字符集
-- 修改数据库字符集
alter database goods character set = 'gbk';

(4)删除数据库

  • 语法:DROP DATABASE [IF EXISTS] 数据库名;
  • DATABASES:必选项
  • IF EXISTS:用于指定在删除数据前,先判断该数据库是否已经存在,可以避免删除不存在的数据库时产生异常
-- 删除数据库goods
drop database if exists goods;

3、数据表操作

(1)创建表

  • 创建表语法:
CREATE TABLE <表名> (
    <列名1> <列类型1>,
    <列名2> <列类型2>,
    <列名3> <列类型3>,
    PRIMARY KEY (<列名1>),
    FOREIGN KEY (<列名2>) REFERENCES <表名2>(<列名2>)
);
  • 列属性语法:
列名 数据类型 [NOT NULL | NULL] [DEFAULT 默认值] [AUTO_INCREMENT] [PRIMARY KEY ] [ FOREIGN KEY ]  [注释]

参数说明:

  • NOT NULL | NULL:该列是否允许是空值;
  • DEFAULT:表示默认值;
  • AUTO_INCREMENT:表示是否是自动编号;
  • PRIMARY KEY:表示是否为主键, 用来标识一条记录(一行),所以每条记录的主键值必须是唯一的。主键可以定义在多列上,这称为联合主键
  • FOREIGN KEY:指定外键关联;
-- 如果没有school库就创建school数据库
create database if not exists school character set = 'utf8mb4';

-- 使用school库
use school;

-- 创建班级表grade
create table grade(
	id int auto_increment,-- id整形,自增
	class_name varchar(20) not null,-- 班级名称,最大长度为20的字符串,不能为空
	primary key (id)-- id为主键
)

-- 在school库中创建学生表
create table student(
	id INT, -- id 整形
	stu_name varchar(20),-- name,最大长度为20的字符串
	class_id INT,-- 对应的班级id
	primary key (id),-- id为主键
	foreign key (id) references grade(id)-- 学生id以班级id为外键
)

(2)复制表

  • 语法:CREATE TABLE 数据表名 LIKE 源数据表名;
    • 数据表名:表示新创建的数据表的名;
    • LIKE 源数据表名:必选项,指定依照哪个数据表来创建新表;
-- 复制表,创建一个和grade结构相同的表teacher表--所有字段名和类型都相同
create table teacher like grade;

(3)查看表

A、查看当前库中所有的表名

  • 语法:SHOW TABLES;
-- 查看当前所使用的库
select database(); -- 查看当前所使用的库,只显示库名
show tables; -- 查看当前使用的库及里面的表,库名及表名都会显示

B、查看表结构

  • 查看表结构:DESCRIBE 数据表名;
  • 查看列结构:DESCRIBE 数据表名 列名;
-- 查看表结构
describe grade;

-- 查看字段结构
describe grade id;

(4)修改表

  • 添加新列:ALTER TABLE 表名 ADD 列名 列属性;
  • 修改列定义:ALTER TABLE 表名 MODIFY 列名 列属性;
  • 修改列名:ALTER TABLE 表名 CHANGE 旧列名 新列名 类型;
  • 删除列:ALTER TABLE 表名 DROP 列名;
  • 修改表名:ALTER TABLE 旧表名 RENAME AS 新表名;
-- 添加新列,老师表加一列课程
alter table teacher add course varchar(20);

-- 修改列定义,老师表课程列类型修改
alter table teacher modify course int;

-- 修改,老师表课程列名修改
alter table teacher change course course_id int;

-- 删除列,删除老师表课程列
alter table teacher drop course_id;

-- 修改表名,修改老师表名
alter table teacher rename as professor;

(5)删除表

  • 语法:DROP TABLE [IF EXISTS] 数据表名;
    • IF EXISTS:可选项,先判断是否存在要删除的表,存在时才执行删除操作;
    • 数据表名:用于指定要删除的数据表名;
-- 删除老师表
drop table if exists professor;

4、数据操作

(1)插入数据

  • 语法:INSERT INTO 数据表名 (列名1, 列名2...) VALUES (值1, 值2...);
    • INTO 数据表名:指定被操作的数据表
    • (列名1, 列名2…):可选项,向数据表的指定列插入数据
    • VALUES(值1, 值2…):需要插入的数据

A、插入全部字段数据

  • 写出全部列名;
  • 不写出全部列表;
-- 查看班级表结构
describe grade;

-- 插入完整数据,写出列名
insert into grade (id,class_name) values (1,'小一班');

-- 插入完整数据,不写出列名
insert into grade values (2,'小二班');

B、 插入部分字段数据

  • 只插入表的一行中的某几个字段的值
-- 插入数据记录的一部分
insert into grade (class_name) values ('小三班');

C、插入多条记录

  • 一次性插入多条数据记录;
-- 一次插入多条记录--完整数据多条记录
insert into grade (id,class_name) values (4,'小四班'),(5,'小五班');

-- 一次插入多条记录--部分字段多条记录
insert into grade (class_name) values ('小六班'),('小七班');

注意事项:

  1. 值与字段必须要对应,位置、个数、数据类型相同;
  2. 值的数据大小,必须在字段指定的长度范围内;
  3. VARCHAR CHAR DATE 类型的值必须使用单引号包裹;
  4. 如果要插入空值,可以忽略不写,或者插入 NULL;
  5. 如果插入指定字段的值,必须要写上列名;

(2)修改数据

  • 语法:UPDATE 数据表名 SET 列名1=值1 [, 列名2=值2...] [WHERE 条件表达式];
    • SET 子句:必选项,用于指定表中要修改的字段名及其字段值
    • WHERE 子句:可选项,满足条件的行
-- 更新修改数据--班级名称全部修改
update grade set class_name = '小一班-修改';

-- 更新修改数据--满足条件的列才进行修改
update grade set class_name = '小一班' where id = 1;

-- 班级表新增一列学生数量
alter table grade add stu_number int;

-- 更新修改数据,一次修改多个值
update grade set class_name = '小二班-优秀',stu_number = 45 where id = 2;

(3)删除数据

  • 通过delete语句删除指定行数据:DELETE FROM 数据表名 WHERE 条件表达式;

    • 数据表名:指定要删除的数据表的表名
    • WHERE 子句:限定表中要删除的行
  • 通过 TRUNCATE TABLE 语句删除全部数据:TRUNCATE TABLE 数据表名;

  • 注意:

    • delete语句是仅仅只删除数据;
    • truncate语句是先把这个表干掉然后再重新创建一个表;
-- 删除指定行数据
delete from grade where class_name = '小一班-修改';

-- 创建一个临时表
create table temp(
	id int
)
-- 给临时表插入数据
insert into temp values (1),(5),(7),(3);

-- 删除全部数据
truncate table temp;

三、SQL查询语句

单表查询操作速查:

场景 关键字 语法 说明
普通查询
查询表中所有数据 * SELECT * FROM 表名;
查询表中部分字段数据 SELECT 列名1,列名2,列名3 FROM 表名;
为字段起别名 as SELECT 列名 AS 列别名 FROM 表名;
查询结果去重 distinct SELECT DISTINCT 列名 FROM 表名;
查询结果参与运算 算术运算 SELECT (列名1 运算表达式1) , (列名2 运算表达式2) FROM 表名;
条件查询 where SELECT 列名1,列名2 FROM 表名 WHERE 条件表达式;
条件表达式
比较运算符 > < <= >= = <> != 比较大小
BETWEEN <起始表达式> AND <结束表达式> select emp_no,salary from salaries where salary between 80000 and 100000; 范围限定区间
in in (50000,60000,70000,80000,90000) 子集限定常量选项,各常量值用逗号隔开
IS [NOT] NULL select emp_no,salary from salaries where salary in (50000,60000,70000,80000,90000); 为空 / 不为空
逻辑运算符
AND或 && select emp_no, birth_date from employees where birth_date = ‘1953-09-02’ and gender = ‘M’; 多个条件同时成立
OR 或|| select salary, from_date from salaries where salary > 80000 or from_date = ‘1985-06-05’; 多个条件任一成立
NOT select emp_no,title from titles where not title=‘Staff’; 不成立
模糊查询 like SELECT 列名1,列名2 FROM 表名 WHERE like 通配符;
% select class_name from grade where class_name like ‘%三%猫%’;-- 包含三和猫:xx三xx猫–三脚猫、张三猫 匹配任意多个字符,注意:如果连着写,给定的字符是有顺序的;使用and连接则不管顺序;
-(下划线) select class_name from grade where class_name like ‘张__’;-- 张开头,三个字符:张xx 匹配一个 字符, 常用来限定表达式的字符长度语句
排序 ORDER BY SELECT 列名 FROM 表名 [WHERE 条件表达式] ORDER BY 列名1 [ASC / DESC], 列名2 [ASC / DESC]; 查询结果排序
单列排序 select salary from salaries where salary > 80000 order by salary desc; 只按照某一个列进行排序
组合排序 select * from salaries where salary < 50000 order by salary desc,emp_no asc; 同时对多个字段进行排序;
聚合函数 SELECT 聚合函数(列名) FROM 表名 数据库系统函数
COUNT() select count(salary) from salaries where salary = 40000; 统计指定列不为 NULL 的记录行数
MAX() select max(salary) from salaries;-- 最高工资 计算指定列的最大值
MIN() select min(salary) from salaries;-- 最低工资 计算指定列的最小值
SUM() select sum(salary) from salaries where emp_no = 10002; 计算指定列的数值和
AVG() select avg(salary) from salaries where emp_no = 10002; 计算指定列的平均值
分组 group by [HAVING 条件] SELECT 分组列/聚合函数 FROM 表名 GROUP BY 分组列 [HAVING 条件]; 分组列:按哪些列进行分组; HAVING:对分组结果再次过滤;
分页查询 limit SELECT 列名1, 列名2… FROM 表名 LIMIT [开始的行数], <查询记录的条数>; limit限制查询结果行数
OFFSET SELECT 列名1, 列名2… FROM 表名 LIMIT <查询记录的条数> OFFSET <开始的行数>; 使用 OFFSET 关键字指定开始的行数

SQL查询语句执行顺序

查询基础语法:

SELECT DISTINCT <列名>
FROM <表名>
WHERE <查询条件表达式>
GROUP BY <分组的列名>
HAVING <分组后的查询条件表达式>
ORDER BY <排序的列名> [ASC / DESC]
LIMIT [开始的行数], <查询记录的条数>

执行顺序:

数据准备

cd 数据所在目录
mysql -h 127.0.0.1 -uroot -p < employees.sql

1、 单表查询

普通查询

  • 查询表中所有数据:SELECT * FROM 表名;
  • 查询表中部分字段数据:SELECT 列名1,列名2,列名3 FROM 表名;
  • 为字段起别名:SELECT 列名 AS 列别名 FROM 表名;
  • 去掉重复信息使用DISTINCT关键字:SELECT DISTINCT 列名 FROM 表名;
  • 查询结果参与运算:SELECT (列名1 运算表达式1) , (列名2 运算表达式2) FROM 表名;
-- 查询部门表中所有数据
select * from departments;

-- 查询员工表中的姓和名
select last_name,first_name from employees;

-- 为工资表中字段部门名起别名
select emp_no as '员工编号',salary as '工资' from salaries ;

-- 查询工资表,去掉重复工资数据
select distinct salary from salaries;

-- 查询员工编号和工资,并给每个工资+500
select emp_no,salary + 500 from salaries;

条件查询where

  • 语法:SELECT 列名1,列名2 FROM 表名 WHERE 条件表达式

  • 条件表达式支持:

    • 比较运算符;
    • 逻辑运算符;
    • like模糊查询和通配符;

(1)比较运算符

运算符 说明
> < <= >= = <> != 比较大小:大于、小于、小于等于、大于等于、等于、不等于
BETWEEN <起始表达式> AND <结束表达式> 范围限定区间
IN 子集限定常量选项,各常量值用逗号隔开
IS [NOT] NULL 为空 / 不为空
-- 比较运算符:查询工资大于80000的员工编号和工资
select emp_no,salary from salaries where salary > 80000;

-- between and 指定区间
select emp_no,salary from salaries where salary between 80000 and 100000;

-- in指定常量选项
select emp_no,salary from salaries where salary in (50000,60000,70000,80000,90000);

-- 为空或不为空,is null / is not null;查询班级表中学生数量为null的班级名称
use school;
insert into grade(class_name) values ('小二班'),('小三班');
select class_name from grade where stu_number is NULL;

(2)逻辑运算符

运算符 说明
AND && 多个条件同时成立
OR || 多个条件任一成立
NOT 不成立
-- 逻辑与:查询出手日期在1953-09-02并且性别为女的所有员工编号和生日
select emp_no, birth_date from employees where birth_date = '1953-09-02' and gender = 'M';

-- 逻辑或:查询工资大于80000或者入职时间为1985-06-05的所有员工工资和入职时间
select salary, from_date from salaries where salary > 80000 or from_date = '1985-06-05';

-- 逻辑非:查询所有title不是Staff的员工编号和title
select emp_no,title from titles where not title='Staff';

(3)模糊查询like+通配符

运算符 说明
% 匹配任意多个字符,注意:如果连着写,给定的字符是有顺序的;使用and连接则不管顺序;
- 匹配一个字符, 常用来限定表达式的字符长度语句

%使用

**注意:**如果连着写,给定的字符是有顺序的;使用and连接则不管顺序;

-- 中间包含“三”的数据都查出来:xxxx三xxxx
select class_name from grade where class_name like '%三%'; 

-- 开头包含三:三xxxx
select class_name from grade where class_name like '三%';

-- 结尾包含三:xxxx三
select class_name from grade where class_name like '%三';

-- 包含三和猫:xx三xx猫--三脚猫、张三猫
select class_name from grade where class_name like '%三%猫%';

-- 三脚猫、张三猫、张猫三--使用and没有顺序限制
select class_name from grade where class_name like '%三%' and class_name like '%猫%';

_使用

  • 表示任意单个字符。匹配单个任意字符,它常用来限定表达式的字符长度语句
-- 张开头,两个字符:张x
select class_name from grade where class_name like '张_';

-- 张开头,三个字符:张xx
select class_name from grade where class_name like '张__';

查询结果排序ORDER BY

  • 语法:SELECT 列名 FROM 表名 [WHERE 条件表达式] ORDER BY 列名1 [ASC / DESC], 列名2 [ASC / DESC];
    • ASC 表示升序排序(默认)
    • DESC 表示降序排序

(1)单列排序

  • 只按照某一个列进行排序, 就是单列排序
-- 满足条件工资降序排列
select salary from salaries where salary > 80000 order by salary desc;

(2)组合排序

  • 同时对多个字段进行排序;
  • 相对第一个字段进行排序,如果第一个字段相同,就按照第二个字段进行排序;
-- 先按照工资降序排列,如果工资相同就按emp_no升序排列
select * from salaries where salary < 50000 order by salary desc,emp_no asc;

聚合函数

  • 语法:SELECT 聚合函数(列名) FROM 表名;
    • COUNT():统计指定列不为 NULL 的记录行数
    • MAX():计算指定列的最大值
    • MIN():计算指定列的最小值
    • SUM():计算指定列的数值和
    • AVG():计算指定列的平均值
-- 查询工资=40000的员工人数
select count(salary) from salaries where salary = 40000;

-- 最高工资
select max(salary) from salaries;

-- 最低工资
select min(salary) from salaries;

-- 查询员工编号为 10002 的员工的薪水总和
select sum(salary) from salaries where emp_no = 10002;

-- 查询员工编号为 10002 的员工的平均薪资
select avg(salary) from salaries where emp_no = 10002;

分组group by [HAVING 条件]

  • 语法:SELECT 分组列/聚合函数 FROM 表名 GROUP BY 分组列 [HAVING 条件];
    • 分组列:按哪些列进行分组
    • HAVING:对分组结果再次过滤
-- 查询每个员工的薪资和,结果按员工编号分组
select emp_no,sum(salary) from salaries group by emp_no;

-- 查询编号小于10100并且薪资和小于50000的员工编号和薪资和,结果按员工编号分组
select emp_no,sum(salary) from salaries where emp_no < 10100 group by emp_no having SUM(salary) < 50000;
-- 结果验证
select emp_no,sum(salary) from salaries where emp_no = 10015;
  • having和where对比:

    • where是对from后面指定的表进行数据筛选,属于对原始数据的筛选;
    • having是对group by分组之后的结果数据进行筛选;
    • having后面的语句中可以使用聚合函数,where后面不可以;

分页查询limit

  • 限制查询结果行数:SELECT 列名1, 列名2... FROM 表名 LIMIT [开始的行数], <查询记录的条数>;
  • 使用 OFFSET 关键字指定开始的行数:SELECT 列名1, 列名2... FROM 表名 LIMIT <查询记录的条数> OFFSET <开始的行数>;
-- 展示前10条员工信息
select * from employees limit 10;
select * from employees limit 0,10;
select * from employees limit 10 offset 0;

-- 查询工资最高前10名员工工资及编号:降序排列之后限制10条
select emp_no,salary from salaries order by salary desc limit 0,10;

-- 工资最高前11到前15员工工资及编号
select emp_no,salary from salaries order by salary desc limit 5 offset 11;

四、SQL约束

  • 对表中的数据进行进一步的限制;
  • 保证数据的正确性、有效性、完整性;
  • 违反约束的不正确数据无法插入到表中;
  • 常见的约束:
    • 主键:PRIMARY KEY
    • 非空:NOT NULL
    • 唯一:UNIQUE
    • 默认:DEFAULT
    • 外键:FOREIGN KEY

1、主键约束

  • 主键:一列(或一组列),其值能够唯一标识表中每一行;
  • 特点:不可重复,唯一,非空;
  • 语法:列名 字段类型 PRIMARY KEY
  • 选择主键原则:
    • 针对业务设计主键,建议每张表都设计一个主键;
    • 主键可以没有业务意义,只需要保证不重复,后期可以对主键值进行修改;

(1)添加主键约束-PRIMARY KEY

  • 创建表的时候设置主键约束;
  • 给已存在的表设置逐渐预算;
创建一个带主键的表
CREATE TABLE emp1(
    -- 设置主键 唯一 非空 
    eid INT PRIMARY KEY, 
    ename VARCHAR(20), 
    sex CHAR(1)
);

-- 给存在的表添加主键
CREATE TABLE emp2( 
    eid INT , 
    ename VARCHAR(20), 
    sex CHAR(1) 
)

-- 通过 DDL 语句进行设置 
ALTER TABLE emp2 ADD PRIMARY KEY(eid);

(2)主键自增-AUTO_INCREMENT

  • AUTO_INCREMENT:表示自动增长(字段类型必须是整数类型)
-- 创建主键自增的表 
CREATE TABLE emp3(
    eid INT PRIMARY KEY AUTO_INCREMENT, 
    ename VARCHAR(20), 
    sex CHAR(1) 
);

(3)设置主键自增的起始值-AUTO_INCREMENT=数字

  • 在创建表参数括号末尾给AUTO_INCREMENT赋值;
-- 创建主键自增的表,自定义自增起始值
CREATE TABLE emp4( 
    eid INT PRIMARY KEY AUTO_INCREMENT, 
    ename VARCHAR(20), 
    sex CHAR(1) 
)AUTO_INCREMENT=100;

(4) 删除主键约束-DROP

  • 语法:ALTER TABLE 表名 DROP PRIMARY KEY;
  • 注意:通过删除表中所有数据的方式是无法删除主键的;
-- 删除表中的主键


-- 使用 DDL 语句删除表中的主键 
ALTER TABLE emp2 DROP PRIMARY KEY; 
-- 查看表结构
DESC emp2;

2、非空约束-NOT NULL

  • 非空约束特点: 某一列不予许为空
  • 语法:列名 字段类型 NOT NULL
-- 添加非空约束
CREATE TABLE emp5( 
    eid INT PRIMARY KEY AUTO_INCREMENT, 
    -- ename 字段不能为空 
    ename VARCHAR(20) NOT NULL, 
    sex CHAR(1) 
);

3、唯一约束-UNIQUE

  • 唯一约束: 表中的某一列的值不能重复
  • 对 NULL 不做唯一的判断
  • 语法:列名 字段类型 UNIQUE
-- 创建带有唯一约束的表  
CREATE TABLE emp6(
    eid INT PRIMARY KEY AUTO_INCREMENT,
    -- 为 ename 字段添加唯一约束
    ename VARCHAR(20) UNIQUE,
    sex CHAR(1) 
);

4、 主键约束与唯一约束的区别

  1. 主键约束,唯一且不能够为空;
  2. 唯一约束,唯一但是可以为空;
  3. 一个表中只能有一个主键,但是可以有多个唯一约束;

5、默认值约束-DEFAULT

  • 默认值约束:用来指定某列的默认值
  • 语法:列名 字段类型 DEFAULT 默认值
-- 创建带有默认值的表 
CREATE TABLE emp7( 
    eid INT PRIMARY KEY AUTO_INCREMENT,
    ename VARCHAR(20), 
    -- 为 sex 字段添加默认值 
    sex CHAR(1) DEFAULT '女'
);

6、外键约束-FOREIGN KEY

  • 主键:可以唯一标识一条记录的列;

  • 外键:从表中与主表的主键对应的字段;

  • 主表:外键所指向的表,约束其他表的表;

  • 从表:外键所在的表,被约束的表;

  • 价值:建立主表与从表的关联关系,为两个表的数据建立连接,约束两个表中数据的一致性和完整性;

(1) 建立外键约束

  • 创建表时添加外键约束:CONSTRAINT [外键约束的名称] FOREIGN KEY (外键字段) REFERENCES [主表名称(主键字段)]

  • 已存在表添加外键约束:ALTER TABLE [表名] ADD CONSTRAINT [外键约束的名称] FOREIGN KEY [外键字段] REFERENCES [主表名称(主键字段)]

# 创建一个关联到主表的从表
CREATE TABLE emp_part(  
    emp_id INT PRIMARY KEY AUTO_INCREMENT,  
    ename VARCHAR(20),  
    age INT ,  
    gender VARCHAR(10),
    dept_id INT,
    -- 添加外键约束 
    CONSTRAINT emp_dept FOREIGN KEY(dept_id) REFERENCES dept(id)
);

(2) 删除外键约束

  • 语法:

    • ALTER TABLE [表名] DROP FOREIGN KEY [外键约束名称]
  • 注意事项

    • 从表外键数据类型必须与主表的主键一致;
    • 删除数据时,需先删除从表数据再删除主表的数据
    • 添加数据时先添加主表数据,再添加从表数据

(3) 级联删除

  • 删除主表数据的同时,也删除掉从表中相关的数据:
    • ON DELETE CASCADE
CREATE TABLE emp_part(
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    ename VARCHAR(20),
    age INT ,
    gender VARCHAR(10), dept_id INT, 
    – 添加外键约束 
    CONSTRAINT emp_dept FOREIGN KEY(dept_id) REFERENCES dept(id) ,
    – 设置允许级联删除 
    ON DELETE CASCADE ); 

# 向员工信息表中添加一条数据 
INSERT INTO emp_part VALUES(1,‘cindy’,20,‘female’,‘2’) ;

#删除主表中部门id=2的部门 
DELETE FROM dept WHERE id=2 ;

# 查看从表中的数据是否同时被删除 
SELECT * FROM emp_part;

五、多表

多表应用场景

  • 多表顾名思义就是在数据库设计中使用多张表格来实现数据存储的要求
  • 在实际的项目开发中,数据量大而且复杂,需要分库分表
  • 分表:按照一定的规则,对原有的数据库和表进行拆分
  • 表与表之间可以通过外键建立连接

多表设计案例:

  • 假定我们现在需要创建一张员工信息表,包含字段:
    • eid 员工ID (自增主键)
    • ename 员工姓名
    • age 年龄
    • gender 性别
    • dept_name 所在部门
    • dept_id 部门ID
    • dept_manager 部门主管
    • dept_location 所在地点

使用单表设计:

CREATE TABLE emp(  
emp_id INT PRIMARY KEY AUTO_INCREMENT,  
ename VARCHAR(20),  
age INT ,  
gender VARCHAR(10),  
dept_name VARCHAR(20),  
dept_id INT,  
dept_manager VARCHAR(20),  
dept_location VARCHAR(20)  
);  

多表设计模式:

  • 将数据拆分为员工信息表employee和部门信息表dept
  • 两个表之间通过部门id:dept_id字段连接
# 创建员工信息表
CREATE TABLE emp_part(  
emp_id INT PRIMARY KEY AUTO_INCREMENT,  
ename VARCHAR(20),  
age INT ,  
gender VARCHAR(10),
dept_id INT,
-- 添加外键约束 
CONSTRAINT emp_dept FOREIGN KEY(dept_id) REFERENCES dept(id)
);

# 创建部门表
CREATE TABLE dept(  
id INT PRIMARY KEY AUTO_INCREMENT,  
dept_name VARCHAR(20),  
dept_manager VARCHAR(20),  
dept_location VARCHAR(20)  
); 

image

多表关系

(1)一对多

  • 定义: 主表的一条记录可以对应从表的多条记录;
  • 例子: 部门表,员工表,一个部门有多个员工,这就是一对多关系;
  • 建表原则:在一对多关系中,一的表定位主表,多的表定为从表,设置外键指向主表;

(2)多对多

  • 定义:主表的多条记录可以对应从表的多条记录;
  • 例子:商品信息表,客户表,订单表;一个商品可以被多个客户购买,一个客户又可以购买多个商品;
  • 建表原则:需要创建第三张表作为中间表中间表需要包含两张表的主键

(3)一对一

  • 定义:从表的一条记录对应主表的一条记录;
  • 例子:员工信息表与身份证表,联系方式;
  • 建表原则: 这种对应关系的数据,通常放在单表里,不用拆成两个表;

六、多表连接查询

  • 连接查询前提条件: 前提是两个表有关联字段,字段名可以不一样,但是业务上必须有关联,不然啥也查不到;

  • 说明=号连接的就是两个表中业务关联的字段;

  • 连接查询分类:

    • 内连接:连接两个表时,取的是两个表中都存在的数据,取交集;可以连续多个表连接,连了再连。。。

      • 隐式内连接:不使用inner join关键字;–(笛卡尔积+where语句)
        • 语法:select * from 表1,表2 where 表1.列 = 表2.列;
      • 显示内连接:使用inner join on关键字;
        • 语法一:select * from 表1 inner join 表2 on 表1.列 = 表2.列;
        • 语法二:select * from 表1 inner join 表2 where 表1.列 = 表2.列;
    • 外连接:查询多个表中相关联的行,有时候需要包含没有关联的行中数据,即返回查询结果集合中不仅包含符合连接条件的行,还包括左表(左连接)、右表(右连接)中的所有数据行。

      • 左连接:连接两个表时,取的是左表中特有的数据,对于右表中不存在的数据,用null来填充;
        • 语法一:select * from 表1 left join 表2 on 表1.列 = 表2.列;
        • 语法二:select * from 表1 left join 表2 where 表1.列 = 表2.列;
      • 右连接:连接两个表时,取的是右表中特有的数据,对于左表中不存在的数据,用null来填充;
        • 语法一: select * from 表1 right join 表2 on 表1.列 = 表2.列;
        • 语法二: select * from 表1 right join 表2 where 表1.列 = 表2.列;
    • 自关联: 自己的某个字段和某个字段有关联;

      • 语法:inner join关联同一个表,不同的字段;
        注意:自关联要用别名;select * from areas as a1 inner join areas as a2 on a1.aid = a2.pid;

七、 子查询

数据准备:

## 创建部门信息表 
drop table if exists dept;

CREATE TABLE dept(  
id INT PRIMARY KEY AUTO_INCREMENT,  
dept_name VARCHAR(20),  
dept_manager VARCHAR(20),  
dept_location VARCHAR(20)  
); 

-- 插入部门数据
INSERT INTO dept VALUES(1,'研发部','张无忌','北京');
INSERT INTO dept VALUES(2,'运营部','赵敏','深圳');
INSERT INTO dept VALUES(3,'销售部','周芷若','成都');

# 创建员工信息表并添加级联删除的外键约束 
drop table if exists emp_part;

CREATE TABLE emp_part(  
emp_id INT PRIMARY KEY AUTO_INCREMENT,  
ename VARCHAR(20),  
age INT ,  
gender VARCHAR(10),
dept_id INT,
salary INT,
-- 添加外键约束 
CONSTRAINT emp_dept FOREIGN KEY(dept_id) REFERENCES dept(id)
-- 设置允许级联删除 
ON DELETE CASCADE
);

-- 插入部门员工数据
INSERT INTO emp_part VALUES(1,'令狐冲',25,'男','1',20000);
INSERT INTO emp_part VALUES(2,'任盈盈',23,'女','1',15000);  
INSERT INTO emp_part VALUES(3,'岳不群',45,'男','1',40000);
INSERT INTO emp_part VALUES(4,'任我行',40,'男','1',30000); 
INSERT INTO emp_part VALUES(5,'岳灵珊',21,'女','1',10000);
INSERT INTO emp_part VALUES(6,'赵灵儿',21,'女','2',7000); 
INSERT INTO emp_part VALUES(7,'林月如',22,'女','2',10000); 
INSERT INTO emp_part VALUES(8,'阿奴',20,'女','2',7000); 
INSERT INTO emp_part VALUES(9,'李逍遥',25,'男','2',15000); 
INSERT INTO emp_part VALUES(10,'景天',28,'男','2',20000);
INSERT INTO emp_part VALUES(11,'邱莹莹',21,'女','3',5000);
INSERT INTO emp_part VALUES(12,'关雎尔',22,'女','3',8000);
INSERT INTO emp_part VALUES(13,'曲筱绡',23,'女','3',10000);
INSERT INTO emp_part VALUES(14,'樊胜美',30,'女','3',10000);
INSERT INTO emp_part VALUES(15,'安迪',28,'女','3',20000);

1、什么是子查询

  • 定义:子查询指一个查询语句嵌套在另一个查询语句内部,在SELECT子句中先计算子查询,子查询的结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。 这个特性从MySQL 4.1开始引入。

  • 子查询作为过滤条件时需要用() 包裹。

  • 子查询场景分类:

    • 子查询充当新表处理:

      • From型子查询:将子查询的结果是多行多列,作为父查询的来使用;
    • 子查询充当条件

      • in/not in 型子查询:子查询的结果是多行单列,作为where的过滤条件;–列子查询 , 子查询结果为列;
      • where型子查询:查询结果是单行单列,作为过滤条件出现在比较运算符的一端;–标量子查询 ,子查询结果唯一;

2、 带From关键词的子查询

  • 子查询是一张多行多列的表,将子查询作为父查询的表来嵌套查询
  • 子查询语句必须用()包裹且需要有别名

案例: 计算出各部门性别为男性的员工人数

-- 先查询出男性员工
select * from emp_part where gender='男';
-- 再将结果作为一个数据源,和部门表合在一起查各部门数量
select dept_name,count(emp_id) from (select * from emp_part where gender='男') as emp INNER JOIN dept where dept.id=emp.dept_id group by dept_name;

3、 带IN关键词的子查询

  • 将子查询作为where语句后的过滤条件,常用于子查询结果是单列多行的情况
  • 子查询语句必须用()包裹
  • in/not in

案例: * 查询出北京地区所有的员工信息

-- 先从部门表中查出部门id,再以部门id为条件在员工表中进行查询
select * from emp_part where dept_id IN (SELECT id FROM dept WHERE dept_location='北京');

-- 不在北京地区的所有员工信息
select * from emp_part WHERE dept_id NOT IN (SELECT id FROM dept WHERE dept_location='北京');

4、 带比较运算符的子查询

  • 将子查询的结果作为过滤条件,放在比较运算符的一端
  • 常用于子查询结果为单个结果的情况
  • 子查询语句必须用()包裹

案例: 查询出薪资大于公司平均薪资的员工id,姓名及薪资

-- 先查出平均薪资,然后以平均薪资为条件进行查询
SELECT AVG(salary) FROM emp_part;

SELECT emp_id,ename,salary FROM emp_part WHERE salary > (SELECT AVG(salary) FROM emp_part);

5、with as语句

  • 如果一整句查询语句中,某个子查询的结果会被多个父查询引用,通常建议将共用的子查询用简写表示出来
  • 语法: with [临时表名] as (select…)
    • 说明:临时表就是后面select查出来的数据组成的结果表,这个结果表会被多次使用,所以用这种方式简化;

案例: 查询出部门平均薪资大于公司平均薪资的部门名称,部门主管,所在地及部门平均薪资

-- 子查询1:查出各部门平均薪资
-- 子查询2:查出公司平均薪资
-- 需要查询:部门名称,部门主管,所在地,部门平均薪资
/*
1、先查出各部门平均薪资--按部门分组聚合
2、将部门平均工资起别名和部门表进行合并
3、再查出公司平均薪资---公司平均薪资有两种方式:对员工表进行平均,对部门平均薪资再进行平均
4、合并之后再根据大于公司平均薪资条件进行查询
*/

# 方式一:
-- 子查询1:查出各部门平均薪资
SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id;
-- 子查询2:查出公司平均薪资--对员工表进行平均
SELECT AVG(salary) from emp_part;

select dept_name,dept_manager,dept_location,dept_avg FROM dept INNER JOIN (SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id) as emp ON emp.dept_id=dept.id and dept_avg > (SELECT AVG(salary) from emp_part);

# 方式二:
-- 子查询1:查出各部门平均薪资
SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id;
-- 子查询2:查出公司平均薪资--对部门平均薪资再进行平均
SELECT AVG(dept_avg) as avg_salary FROM (SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id) as da;

select dept_name,dept_manager,dept_location,dept_avg FROM dept INNER JOIN (SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id) as emp ON emp.dept_id=dept.id and dept_avg > (SELECT AVG(dept_avg) as avg_salary FROM (SELECT dept_id,AVG(salary) as dept_avg FROM emp_part group by dept_id) as da);

# 方式三:使用with [临时表名] as 语句
-- 因为上面的方式对部门平均薪资进行了多次使用,所以将部门平均薪资作为一临时结果表使用
WITH dept_avg AS (SELECT dept_id,AVG(salary) as dept_avg_salary FROM emp_part group by dept_id)select dept_name,dept_manager,dept_location,dept_avg_salary FROM dept INNER JOIN dept_avg ON dept_avg.dept_id=dept.id and dept_avg_salary > (SELECT avg(dept_avg_salary) from dept_avg);

6、视图

  • 定义:视图是一种虚拟的表,它并不会在你的存储空间复制一份数据,而是对原有数据的一种引用。可以将视图理解为一种存储起来的sql语句也可以理解为定义的临时表变量,在其他sql中可以使用这个变量,with as定义的临时变量表只能在本SQL中使用;
  • 视图可以简化多表查询;
  • 视图也可以用于控制用户权限;
  • 使用关键词view来创建视图;
  • 语法:CREATE VIEW [视图名称] AS SELECT……
CREATE VIEW temp_dept AS (
    SELECT
        order_list.dept_id,
        city,
        manager,
        SUM( volume ) total_volume 
    FROM
        order_list
        INNER JOIN department ON order_list.dept_id = department.dept_id 
    GROUP BY
        order_list.dept_id 
    ORDER BY
        SUM( volume ) DESC 
    );
    
SELECT
    * 
FROM
    temp_dept 
WHERE
    total_volume >(
    SELECT
        AVG( total_volume ) 
FROM
    temp_dept);

#查询出最近两周的冠军销售部门

SELECT * FROM temp_dept WHERE total_volume=(SELECT max(total_volume) FROM temp_dept);

八、数据库进阶

1、MySQL中SQL执行原理

(1)SQL语句执行过程

  • 存储引擎:说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和操作此表的类型)。

(2)MySQL Server组件

  • 连接器:连接管理,权限验证;
  • 查询缓存:命中直接返回结果;
  • 分析器:语法分析;
  • 优化器:生成执行计划,选择索引;
  • 执行器:操作引擎,返回结果;

2、索引

(1)什么是索引

  • 索引是存储在表中一个特定列的值数据结构
  • 索引包含一个表中列的值,并且这些值存储在一个数据结构中;

(2)索引分类

  • 单列索引:一个表中可以有多个单列索引;
    • 普通索引
    • 唯一索引:允许 NULL 值
    • 主键索引:不允许 NULL 值
  • 组合索引
  • 全文索引

(3)索引优势与劣势

  • 优势:

    • 提高数据检索的效率,降低数据库的 IO 成本
    • 通过索引对数据进行排序,降低数据排序的成本,降低了 CPU 的消耗
  • 劣势:

    • 占用空间
    • 降低更新表的速度
    • 需要花时间研究建立最优秀的索引,或者优化

(4)索引适合的场景

  • 主键自动建立唯一索引
  • 频繁作为查询条件的字段应该创建索引
  • 查询中与其他表关联的字段,外键关系建立索引
  • 查询中排序的字段

3、explain

(1)什么是explain

explain即查看执行计划 ,使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MYSQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈

(2)explain有什么用

(1)表的读取顺序
(2)数据读取操作的操作类型
(3)哪些索引可以使用
(4)哪些索引被实际使用
(5)表之间的引用
(6)每张表有多少行被优化器查询

(3)explain使用

  • explain + SQL 语句

explain的信息组成如下:

4、事务

(1)什么是数据库事务

  • 数据库事务 ( transaction) 是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
  • 事务由事务开始与事务结束之间执行的全部数据库操作组成

(2)事务特点 - ACID

1、A (Atomicity) 原子性

原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

2、C (Consistency) 一致性

一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

3、I (Isolation) 独立性

所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。

比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

4、D (Durability) 持久性

持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

(3)事务操作

  • begin 开始一个事务
  • rollback 事务回滚
  • commit 事务提交

5、日志