数据库MySQL

1. 数据库的概念

数据库是用于存储和管理数据的仓库。

特点:

  1. 持久化存储数据(数据库其实就是一个文件系统);
  2. 方便存储和管理数据;
  3. 使用了统一的方式操作数据库(即SQL)。

常见的的数据库软件:Oracle、MySQL、DB2等。

2. MySQL数据库软件

启动:

  1. 手动
  2. cmd -> services.msc 打开服务的窗口再手动启动
  3. 使用管理员打开cmd
    • net start mysql(数据库名):开启
    • net stop masql:关闭

登录:

  • mysql -uroot -p密码(如果不想让人看到密码可以回车后再输密码)
  • mysql -hip(连接目标的ip) -uroot -p连接目标的密码
  • mysql --host=ip --user=root --passvord=连接目标的密码

退出:

  • exit
  • quit

3. SQL

结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。每一种数据库操作的方式会有一些不一样的地方

通用语法:

  1. SQL语句可以单行或多行书写,以分号为结尾;
  2. 可以使用空格和缩进来增强语句的可读性;
  3. MySQL数据库的SQL语句不区分大小写,关键字建议使用大写;
  4. 3 种注释方法:
    • 单行注释:-- 注释内容 或 # 注释内容(mysql特有),注意–后面需要加空格,#可加可不加
    • 多行注释:/* 注释内容 */

mysql分类:

  • DDL:数据定义语言,用于操作数据库、表等;
  • DML:数据操作语言,用于增删改表中的数据;
  • DQL:数据查询语言,用于查询表中的数据;
  • DCL:数据控制语言,用于定义数据库的访问权限和安全级别及创建用户。
3.1 DDL

操作数据库(CRUD):

  • C(Create):创建

    • 直接创建:create database 数据库名称
    • 判断是否存在,不存在则创建:create database if not exists 数据库名称
    • 创建指定字符集的数据库:create database 数据库名称 character set 字符集名
  • R(Retrieve):查询

    • 查询所有数据库的名称:show databases
    • 查询某个数据库的字符集(即查询某个数据库的创建语句):show create database 数据库名称
  • U(Update):修改

    • 修改数据库的字符集:alter database 数据库名称 character set 字符集名称
  • D(Delete):删除

    • 直接删除:drop database 数据库名称
    • 判断是否存在,存在再删除:drop database if exists 数据库名称
  • 使用数据库

    • 查询当前正在使用的数据库名称:select database()
    • 使用数据库:use 数据库名称

操作表:

  • C(Create):创建
    • 语法:
      create table 表名 (
      列名1 数据类型1,
      列名2 数据类型2,

      列名n 数据类型n
      );
      注意:最后一列不需要加逗号
    • 数据库类型:
      整数 int
      小数 double(共有多少位, 小数点后有多少位)
      日期 date,只包含年月日,yyyy-MM-dd
      日期 datetime,包含年月日时分秒 yyyy-MM-dd HH:mm:ss(如果不给这个字段赋值或赋值null,则默认使用当前的系统时间来自动赋值)
      字符串 varchar(最大长度)
-- 创建表
create table student(
id int,
name varchar(32),
age int,
score double(4,1),
birthday date,
insert_time timestamp
);
复制表:create table 表名 like 被复制表名
  • R(Retrieve):查询

    • 查询某个数据库中所有表的名称:show tables
    • 查询表结构:desc 表名
  • U(Update):修改

    • 修改表名:alter table 表名 rename to 新表名
    • 修改表的字符集:alter table 表名 character set 字符集名称
    • 添加一列:alter table 表名 add 列名 数据类型
    • 修改列名称、类型:
      alter table 表名 change 列名 新列名 新数据类型
      alter table 表名 modify 列名 新数据类型
    • 删除列:alter table 表名 drop 列名
  • D(Delete):删除

    • 直接删除:drop table 表名
    • 判断是否存在再删除:drop table if exists 表名
3.2 DML

添加数据:

  • 语法:insert into 表名(列名1,列名2,…列名n) values(值1,值2,…值n)
  • 注意:
    • 列名和值要一一对应;
    • 如果表名后不定义列名,则默认给所有列添加值;
    • 除了数字类型,其他类型的值都需用引号引起来(单双都行)

删除数据:

  • 语法:delete from 表名 where 条件
  • 注意:如果不写where 条件,则删除表中所有记录
  • 如果要删除所以记录
    • delete from 表名(不推荐,有多少条记录就会执行多少次删除操作)
    • truncate table 表名(先删除表,再创建一个一样的表)

修改数据:

  • 语法: update 表名 set 列名1=值1, 列名2=值2… where 条件
  • 注意:如果不加条件,则会将表中所有记录全部修改
3.3 DQL

语法:
select 字段列表
from 表名列表
where 条件列表
group by 分组字段
having 分组之后的条件
order by 排序
limit 分页限定

基础查询:

  1. 多个字段的查询:select 字段名1, 字段名2, … from 表名
  2. 查询全部字段:select * from 表名
  3. 去除重复:distinct
  4. 计算列:
    • 一般可以使用四则运算来计算一些列的值
    • null参加的计算,结果都为null
    • ifnull(表达式1, 表达式2):如果为null,则用表达式2将表达式1替换掉
  5. 起别名:as
CREATE TABLE student (
id INT,   -- 编号
NAME VARCHAR(20),  -- 姓名
sex VARCHAR(5),  -- 性别
address VARCHAR(20),  -- 地址
math INT,  -- 数学成绩
english INT  -- 英语成绩
);

INSERT INTO student VALUES (1, '猪猪侠', '男', '某某镇', 80, 80), (2, '小菲菲', '女', '某某镇', 85, 90), 
(3, '超人强', '男', '某某镇', 90, 80), (4, '熊大', '男', '树林', 70, 80), (5, '熊二', '男', '森林', 70, 75);

INSERT INTO student VALUES (6, '路人甲', '男', '某某镇', 80, NULL);

SELECT * FROM student;  -- 查询全部

SELECT NAME, id FROM student;   -- 查询姓名和编号

SELECT address FROM student;

SELECT DISTINCT address FROM student;   -- 查询地址并去重

-- 计算math和england的和
SELECT NAME, math, english, math + english FROM student;  -- 如果有null参加的计算结果都为null

-- 解决为null的情况
SELECT NAME, math, english, IFNULL(math, 0) + IFNULL(english, 0) FROM student;

-- 起别名(将IFNULL(math, 0) + IFNULL(english, 0)换名为总分)
SELECT NAME, math, english, IFNULL(math, 0) + IFNULL(english, 0) AS 总分 FROM student;
SELECT NAME, math, english, IFNULL(math, 0) + IFNULL(english, 0) 总分 FROM student;  -- as可省略

条件查询:

  1. where后根条件
  2. 运算符
    大于 > ,小于 <, 大于等于 >= , 小于等于<=, 等于=, 不等于 <>,
    AND 与, OR 或, NOT 非, IN 集合
    LIKE 模糊查询:占位符_:单个任意字符、%:任意字符
-- 查询编号等于1
SELECT * FROM student WHERE id = 1;

-- 查询编号大于等于3
SELECT * FROM student WHERE id >= 3;

-- 查询编号大于等于3小于等于5
SELECT * FROM student WHERE id >= 3 && id <= 5;
SELECT * FROM student WHERE id >= 3 AND id <= 5;
SELECT * FROM student WHERE id BETWEEN 3 AND 5;

-- 查询编号1、3、5的信息
SELECT * FROM student WHERE id = 1 OR id = 3 OR id = 5;
SELECT * FROM student WHERE id IN (1, 3, 5);

-- 查询英语成绩为null的
SELECT * FROM student WHERE english = NULL;  -- 错误写法,null值不能用=(!=)判断
SELECT * FROM student WHERE english IS NULL;

SELECT * FROM student WHERE english IS NOT NULL;

-- 查询姓熊的
SELECT * FROM student WHERE NAME LIKE '熊%';

-- 查询第二个字是人的
SELECT * FROM student WHERE NAME LIKE '_人%';

排序查询:

  1. 语法:order by 排序字段1 排序方式1, 排序字段2 排序方式2…
  2. 排序方式:asc 升序,默认的。 desc 降序。

聚合函数: 将一列数据作为一个整体,进行纵向的计算。

  • count:计算个数
  • max:计算最大值
  • min:计算最小值
  • sum:计算和
  • avg:计算平均数
  • 注意:在计算时,会把null值排除。

分组查询:

  • 语法:group by 分组字段
  • 注意:分组之后查询的字段:分组字段、聚合函数
  • where 和 having 的区别:where 在分组之前进行限定,如果不满足条件,则不参与分组。having 在分组之后进行限定,如果不满足结果,则不会被查询出来。where 后不可以跟聚合函数,having可以进行聚合函数的判断。

分页查询:

  • 语法:limit 开始的索引, 每页查询的条数
  • 开始的索引 = (当前的页码 - 1) * 每页显示的条数
  • limit 是一个 mysql “方言”
-- 按数学成绩排序
SELECT * FROM student ORDER BY math;  -- 默认的,升序
SELECT * FROM student ORDER BY math ASC;  -- 升序
SELECT * FROM student ORDER BY math DESC;  -- 降序

-- 按数学成绩排序,若数学成绩一样则按英语成绩排
SELECT * FROM student ORDER BY math ASC, IFNULL(english, 0) ASC;

-- 聚合函数
SELECT COUNT(NAME) FROM student;
SELECT MAX(math) FROM student;
SELECT MIN(math) FROM student;
SELECT SUM(english) FROM student;
SELECT AVG(IFNULL(english, 0)) FROM student;

-- 按照性别分组,分别查看平均分
SELECT sex, AVG(math) FROM student GROUP BY sex;

-- 按照性别分组,分别查看平均分, 分数低于70的不参与分组
SELECT sex, AVG(math) FROM student WHERE math > 70 GROUP BY sex;

-- 按照性别分组,分别查看平均分, 分数低于70的不参与分组,分组人数需要大于1
SELECT sex, AVG(math) FROM student WHERE math > 70 GROUP BY sex HAVING COUNT(sex) > 1;

-- 每页显示三条记录
SELECT * FROM student LIMIT 0, 3;  -- 第一页
SELECT * FROM student LIMIT 3, 3;  -- 第二页
3.4 DCL

DBA: 数据库管理员

DCL: 管理用户、授权

  • 管理用户
    1. 添加用户:create user ‘用户名’@‘主机名’ identified by ‘密码’
    2. 删除用户:drop uesr ‘用户名’@‘主机名’
    3. 修改用户密码:
      update user set password = password(‘新密码’) where user = ‘用户名’
      set password for ‘用户名’@‘主机名’ = password(‘新密码’)
    4. 查询用户:
      切换到MySQL数据库:use mysql
      查询user表:select * from user
      注意:通配符%表示可以在任意主机使用用户登录数据库
  • 权限管理
    1. 查询权限:show grants for ‘用户名’@‘主机名’
    2. 授予权限:grant 权限列表 on 数据库.表名 to ‘用户名’@‘主机名’
    3. 撤销权限:revoke 权限列表 on 数据库名.表名 from ‘用户名’@‘主机名’

4. 约束

概念: 对表中的数据进行限定,保证数据的正确性、有效性和完整性。

分类:

  1. 主键约束:primary key,非空且唯一
  2. 非空约束:not null,某一列的值不能为null
  3. 唯一约束:unique,某一列的值不能重复
  4. 外键约束:foreign key
4.1 非空约束
  1. 在创建表时添加约束
  2. 创建表完后,添加非空约束
  3. 删除非空约束
CREATE TABLE stu (
	id INT,
	NAME VARCHAR(20) NOT NULL  -- name为非空
);

-- 删除name的非空约束
ALTER TABLE stu MODIFY NAME VARCHAR(20);

-- 创建表后,添加非空约束
ALTER TABLE stu MODIFY NAME VARCHAR(20) NOT NULL;
4.2 唯一约束
  1. 在创建表时添加约束
  2. 创建表完后,添加唯一约束
  3. 删除唯一约束

注意:唯一约束可以有null值,但是有且仅有一个null

-- 创建表时添加唯一约束
CREATE TABLE stu (
	id INT UNIQUE,   -- 编号唯一
	NAME VARCHAR(20)
);

-- 删除唯一约束
ALTER TABLE stu DROP INDEX id;

-- 创建表后,添加唯一约束
ALTER TABLE stu MODIFY id INT UNIQUE;
4.3 主键约束

注意:

  • 含义:非空且唯一
  • 一张表只能有一个字段为主键
  • 主键就是表中记录的唯一标识
  1. 在创建表时添加约束
  2. 创建表完后,添加主键约束
  3. 删除主键约束
-- 创建表时添加主键约束
CREATE TABLE stu (
	id INT PRIMARY KEY,   -- 给编号添加主键约束
	NAME VARCHAR(20)
);

-- 删除主键约束
ALTER TABLE stu DROP PRIMARY KEY;

-- 创建表后,添加唯一约束
ALTER TABLE stu MODIFY id INT PRIMARY KEY;

自动增长: 如果某一列是数值类型的,使用 auto_increment 可以来完成值的自动增长。

-- 创建表时添加主键约束,并且设置主键自动增长
CREATE TABLE stu (
	id INT PRIMARY KEY AUTO_INCREMENT,   -- 给编号添加主键约束
	NAME VARCHAR(20)
);

-- 删除自动增长
ALTER TABLE stu MODIFY id INT;

-- 添加自动增长
ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;

注意:自动增长是按照上一个数据增长的,若为第一个数据,则从1开始

4.4 外键约束
  • 在创建表时,可以添加外键约束
    create table 表名(

    外键列
    constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称)
    );

  • 删除外键
    ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;

  • 创建表之后,添加外键
    ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键列名称) REFERENCES 主表名称(主表列名称);

-- 创建部门表
CREATE TABLE department (
	id INT PRIMARY KEY AUTO_INCREMENT,
	dep_name VARCHAR(20),
	dep_location VARCHAR(20)
);

-- 创建员工表
CREATE TABLE employee (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	age INT,
	dep_id INT,  -- 外键对应主表的主键
	CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id)
);

INSERT INTO department VALUES (1, '研发部', '上海'), (2, '销售部', '广州');
INSERT INTO employee VALUES (NULL, '小红', 25, 1), (NULL, '小明', 26, 2), (NULL, '小林', 24, 1), (NULL, '小刚', 25, 2);

-- 删除外键
ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;

-- 添加外键
ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id);

外键值可以为null,但不能为不存在的外键值

级联操作: 当主表更改时,从表跟从更改。

  • 级联更新:ON UPDATE CASCADE
  • 级联删除:ON DELETE CASCADE
-- 添加外键,设置级联更新
ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id) ON UPDATE CASCADE;

-- 添加外键,设置级联更新,设置级联删除(可以和更新分开添加)
ALTER TABLE employee ADD CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id) ON UPDATE CASCADE ON DELETE CASCADE;

5. 多表关系

一对多
实现方式:在多的一方建立外键,指向一的一方的主键。

多对多
实现方式:需要借助第三张表,中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键。

一对一
实现方式:可以在任意一方添加被唯一约束的外键指向另一方的主键。

案例:

-- 旅游路线分类表
CREATE TABLE tab_category (
	cid INT PRIMARY KEY AUTO_INCREMENT,
	cname VARCHAR(100) NOT NULL UNIQUE
);

-- 旅游线路表
CREATE TABLE tab_route (
	rid INT PRIMARY KEY AUTO_INCREMENT,
	rname VARCHAR(20) NOT NULL UNIQUE,
	price INT,
	cid INT,  -- 外键分类
	FOREIGN KEY (cid) REFERENCES tab_category(cid)   -- 省略了外键名称,系统会自动分配
);

-- 用户表
CREATE TABLE tab_user (
	uid INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(100) NOT NULL UNIQUE,
	PASSWORD VARCHAR(10) NOT NULL,
	sex VARCHAR(5)
);

-- 中间表,关联用户表和线路表,多对多
CREATE TABLE tab_like (
	rid INT,  -- 线路id
	uid INT,  -- 用户id
	-- 创建复合主键
	PRIMARY KEY(rid, uid),  -- 联合主键
	FOREIGN KEY (rid) REFERENCES tab_route(rid),
	FOREIGN KEY (uid) REFERENCES tab_user(uid)
);

在这里插入图片描述

6. 范式

范式:符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度。数据库范式也分为1NF,2NF,3NF,BCNF,4NF,5NF。

一般在我们设计关系型数据库的时候,最多考虑到BCNF就够。符合高一级范式的设计,必定符合低一级范式,例如符合2NF的关系模式,必定符合1NF。

第一范式: 每一列都是不可分割的源自数据项。实际上,1NF是所有关系型数据库的最基本要求。

第二范式: 在1NF的基础之上,非码属性必须完全依赖于候选码(在1NF的基础之上消除了非主属性对主码的部分函数依赖)。

  • 函数依赖: 如果通过A属性(属性组)的值,可以确定唯一B属性的值,则称B依赖于A;
  • 完全函数依赖:如果A是一个属性组,而B属性值得到确定需要依赖于A属性组中所有的属性值;
  • 部分函数依赖:如果A是一个属性组,则B属性值的确定只需要依赖于A属性组中某一些值即可;
  • 传递函数依赖:如果通过A属性(属性组)的值,可以确定唯一B属性的值,再通过B属性(属性组)的值,可以确定唯一C属性的值,则称C传递函数依赖于A
  • 码:如果在一张表中,一个属性或属性组被其它属性完全依赖,则称这个属性(属性组)为该表的码。
    • 主属性:码属性组中所有的属性
    • 非主属性:除过码属性组的属性

第三范式: 在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)。

详情参考:https://blog.csdn.net/wenco1/article/details/88077279

7. 数据库的备份和还原

备份: mysqldump -u用户名 -p密码 需要备份的数据库名称 > 保存备份的路径

还原:

  1. 登录数据库
  2. 创建数据库
  3. 使用数据库
  4. 执行文件:source 文件路径

8. 多表查询

查询语法: select 列名列表 from 表名列表 where 条件

笛卡尔积: 有两个集合A、B,取这两个集合的所有组合情况。

如果要完成多表查询,就要消除无用的数据

8.1 内连接
  • 内连接查询
    • 隐式内连接:使用where条件消除无用数据
    • 显式内连接:select 字段列表 from 表名1 inner(可省略) join 表名2 on 条件
-- 只查询名字和对应的部门名(隐式内连接)
SELECT employee.`name`, department.`dep_name` FROM employee, department WHERE employee.`dep_id` = department.`id`;

-- 别名替换
SELECT 
	t1.`name`,
	t2.`dep_name` 
FROM 
	employee t1, 
	department t2 
WHERE 
	t1.`dep_id` = t2.`id`;
	
-- 显式内连接
SELECT employee.`name`, department.`dep_name` FROM employee INNER JOIN department ON employee.`dep_id` = department.`id`;
8.2 外连接
  • 外连接查询
    • 左外连接:查询的是左表所有数据及其交集部分
      select 字段列表 from 表1 left outer(可省略) join 表2 on 条件
    • 右外连接:查询的是右表所有数据及其交集部分
      select 字段列表 from 表1 right outer(可省略) join 表2 on 条件
-- 左外连接
SELECT 
	t1.*,
	t2.`dep_name`
FROM
	employee t1
LEFT OUTER JOIN
	department t2
ON
	t1.`dep_id` = t2.`id`;

-- 右外连接
SELECT 
	t1.*,
	t2.`dep_name`
FROM
	employee t1
RIGHT OUTER JOIN
	department t2
ON
	t1.`dep_id` = t2.`id`;
8.3 子查询

概念: 查询中嵌套查询,称嵌套查询为子查询

-- 查询年龄最大的员工信息
SELECT * FROM employee WHERE employee.`age` = (SELECT MAX(age) FROM employee);

子查询的不同情况:

  1. 子查询的结果是单行单列的:子查询可以作为条件,使用>,<,=等去判断
  2. 子查询的结果是多行单列的:子查询可以作为条件,使用in去判断
  3. 子查询的结果是多行多列的:子查询可以作为一张虚拟表去查询
-- 查询年龄小于平均年龄的员工信息(单行单列)
SELECT * FROM employee WHERE employee.`age` < (SELECT AVG(age) FROM employee);

-- 查询研发部的所有员工信息(多行单列)
SELECT * FROM employee WHERE dep_id IN (SELECT id FROM department WHERE dep_name = '研发部');

-- 查询24岁以上的员工信息和对应的部门信息(多行多列)
SELECT * FROM department t1, (SELECT * FROM employee WHERE age > 24) t2 WHERE t1.`id` = t2.dep_id;
8.4 练习
-- 部门表
CREATE TABLE dept (
	id INT PRIMARY KEY AUTO_INCREMENT,
	dname VARCHAR(20),  -- 部门名称
	loc VARCHAR(20)     -- 部门所在地
);

INSERT INTO dept VALUES (10, '教研部', '北京'), (20, '学工部', '上海'), (30, '销售部', '广州'), (40, '财务部', '深圳');

-- 职位表
CREATE TABLE job (
	id INT PRIMARY KEY AUTO_INCREMENT,
	jname VARCHAR(20),   -- 职位名称
	description VARCHAR(20)  -- 职位描述
);

INSERT INTO job (jname, description) VALUES ('董事长', '管理公司'), ('经理', '管理员工'), ('销售员', '推销产品'), ('文员', '办公');

-- 员工表
CREATE TABLE emp (
	id INT PRIMARY KEY AUTO_INCREMENT,
	ename VARCHAR(10),
	job_id INT,   -- 职务id
	mgr INT,  -- 上级领导
	salary DOUBLE(7, 2),  -- 工资
	dept_id INT,  -- 所属部门
	FOREIGN KEY (job_id) REFERENCES job(id),
	FOREIGN KEY (dept_id) REFERENCES dept(id)
);

INSERT INTO emp (ename, job_id, mgr, salary, dept_id) VALUES
('小红', 4, 4, 6000.00, 40), 
('小明', 4, 4, 6200.00, 20), 
('小林', 3, 2, 5000.00, 10), 
('小刚', 2, 5, 7100.00, 30),
('小刘', 1, NULL, 8500.00, 40);

-- 工资等级表
CREATE TABLE salarygrade (
	grade INT PRIMARY KEY AUTO_INCREMENT,  -- 等级
	low INT,  -- 最低
	high INT  -- 最高
);

INSERT INTO salarygrade (low, high) VALUES (7500, 10000), (6500, 7500), (5500, 6500), (4500, 5500);

SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM job;

-- 查询员工信息和职务名称即描述
SELECT emp.`id`, emp.`ename`, emp.`salary`, job.`jname`, job.`description` FROM emp INNER JOIN job ON emp.`job_id` = job.`id`;

-- 查询员工信息、职务名称即描述、部门名称即位置
SELECT 
	emp.`id`, emp.`ename`, emp.`salary`, job.`jname`, job.`description`, dept.`dname`, dept.`loc` 
FROM
	emp, job, dept
WHERE
	emp.`job_id` = job.`id` AND emp.`dept_id` = dept.`id`;
	
-- 查询员工工资即工资等级
SELECT
	emp.`ename`, emp.`salary`, salarygrade.`grade`
FROM
	emp, salarygrade
WHERE
	-- 两种写法
	-- emp.`salary` >= salarygrade.`low` and emp.`salary` < salarygrade.`high`; 
	emp.`salary` BETWEEN salarygrade.`low` AND salarygrade.`high`; 

-- 查询员工信息、职务名称即描述、部门名称即位置、工资即工资等级
SELECT 
	emp.`ename`, emp.`salary`, job.`jname`, job.`description`, dept.`dname`, dept.`loc`, salarygrade.`grade` 
FROM
	emp, job, dept, salarygrade
WHERE
	emp.`job_id` = job.`id` AND emp.`dept_id` = dept.`id` AND emp.`salary` BETWEEN salarygrade.`low` AND salarygrade.`high`;

-- 查询部门信息即人数
SELECT
	t1.`id`, t1.`dname`, t1.`loc`, t2.total
FROM
	dept t1, (
	SELECT
		dept_id, COUNT(id) total
	FROM
		emp
	GROUP BY
		dept_id) t2
WHERE
	t1.`id` = t2.dept_id;

-- 查询所有员工姓名即上级姓名(没有查看到没有上级的人)
SELECT
	t1.`ename`, t1.`mgr`, t2.`id`, t2.`ename`
FROM
	emp t1, emp t2
WHERE
	t1.`mgr` = t2.`id`;
	
-- 查询所有员工姓名即上级姓名(可以查看到没有上级的人)
SELECT t1.`ename`, t1.`mgr`, t2.`id`, t2.`ename` FROM emp t1 LEFT JOIN emp t2 ON t1.`mgr` = t2.`id`;

9. 事务

概念: 如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。

操作:

  1. 开启事务:start transaction
  2. 回滚:rollback
  3. 提交:commit
9.1 默认自动提交 & 手动提交

自动提交:

  • MySQL数据库中事务默认自动提交;
  • 一条DML(增删改)语句会自动提交一次事务。

手动提交:

  • Oracle 数据库默认是手动提交;
  • 需要先开启事务,再提交。

修改事务的默认提交方式

  1. 查看事务的默认提交方式:select @@autocommit; (1代表自动提交,0代表手动提交)
  2. 修改默认提交方式:set @@autocommit = 0或1
9.2 事务四大特征
  1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败;
  2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据;
  3. 隔离性:多个事务之间,相互独立;
  4. 一致性:事务操作前后,数据总量不变。
9.3 事务隔离级别

概念: 多个事务之间是隔离的,相互独立的。如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。

存在问题:

  1. 脏读:一个事务,读取到另一个事务中没有提交的数据;
  2. 不可重复读:在同一个事务中,两次读取到的数据不一样;
  3. 幻读:一个事务操作数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。

隔离级别:

  • read uncommitted:读未提交,产生的问题:脏读、不可重复读、幻读;
  • read committed:读已提交,产生的问题:不可重复读、幻读;(Oracle默认)
  • repeatable read:可重复读,产生的问题:幻读;(MySQL默认)
  • serializable:串行化,可以解决所有的问题

注意:隔离级别从小到大安全性越来越高,但是效率越来越低

数据库隔离级别查询: select @@tx_isolation(个别版本:SELECT @@transaction_isolation;)

数据库隔离级别设置: set global transaction isolation level 级别字符串

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值