0413
第一、二、三、四、五章
六、事务(TRANSACTION)
28.事务ACID原则、脏读、不可重复读、幻读
1.什么是事务?
事务就是将
一组SQL语句放在同一批次内去执行
;
如果
一个SQL语句出错
,则该批次内的
所有SQL都将被取消执行
;(要么都成功,要么都失败)
MySQL事务处理只支持
InnoDB
和BDB数据表类型。
2.事务原则(巨重要)
ACID
原则:
原子性(Atomicity) 、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
(脏读,幻读,不可重复读…)
参考博客链接:
事务ACID理解
原子性(Atomicity):
-
原子性是指事务是一个
不可分割的工作单位
,
事务中的操作要么都发生,要么都不发生
。或者说是两个操作要么一起成功,或者一起失败,不能只发生其中一个动作。
一致性(Consistency):
-
事务前后数据的完整性必须保持一致。针对一个事务
操作前与操作后
的状态一致。例如:两个人转账,两人一共1000块,操作前和操作后的总和都是1000。
隔离性(Isolation):
-
事务的隔离性是
多个用户并发访问数据库时
,数据库为每一个用户开启的事务,不
能被其他事务的操作数据所干扰
,多个并发事务之间要相互隔离。
持久性(Durability):
-
持久性是指
一个事务一旦被提交
,它对数据库中数据的
改变就是永久性的
,接下来
即使数据库发生故障也不应该对其有任何影响
,即
事务结束后
的数据不会因为外界原因导致数据丢失; -
举例:
操作前A:800,B:200
操作后A:600,B:400
如果在
操作前(事务还没有提交)服务器宕机或者断电
,那么重启数据库以后,数据状态应该为
A:800,B:200 – 相当于没发生,回滚到事务开始前的状态
如果在
操作后(事务已经提交)服务器宕机或者断电
,那么重启数据库以后,数据状态应该为
A:600,B:400 – 即实务操作成功后,带来的改变是不可逆的。
隔离所导致的一些问题:
①
脏读(Dirty Read)
:
-
指
一个事务读取了另外一个事务未提交的数据
的现象就是
脏读
。 -
例如:
在事务A执行过程中,事务A对数据资源进行了修改,事务B读取了事务A
修改后的数据
;
由于某些原因,事务A并没有完成提交,发生了
RollBack
操作,则事务B读取的数据就是
脏数据
。
②
不可重复读(Nonrepeatable Read)
:
-
在同一个事务中读取表中的某一行数据,
前后两次读取的数据不一致
的现象就是
不可重复读(Nonrepeatable Read)
。(这个不一定是错误,只是某些场合不对) -
例如:
事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的数据不一致。 -
不可重复读强调的是
单条数据的更新
。
③虚读(幻读):
-
是指
在一个事务内读取到了别的事务插入的数据
,导致
前后读取数量总量不一致
。(一般是
行影响
,如下图所示:多了一行) -
例如:
事务B前后两次读取同一个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后一次读取到前一次查询没有看到的行。 -
幻读强调的是
整个集合的增减
。
注意:
幻读和不可重复读有些类似,但是幻读强调的是
集合的增减
,而不可重复读强调的是
单条数据的更新
。
29. 测试事务实现转账
执行事务:(原理)
mysql 是默认
开启事务自动提交
,即
autocommit = 1
所以要手动处理事务,就要①先关闭(系统默认的)事务自动提交的设置:
-- 关闭
SET autocommit = 0;
②然后就可以手动处理事务了,先开启事务:
-- 事务开启
START TRANSACTION; -- 标记一个事务的开始,从这个之后的sql都在同一个事务内
③然后是一组sql:
INSERT XX
INSERT XX
④执行完这一组sql,可以有以下两种操作:
-- 回滚 : 只要没COMMIT,就还可以滚回到的原来的样子
ROLLBACK;
-- 提交 : 持久化(一旦提交,再回滚也滚不回去了)
COMMIT;
⑤最后结束手动处理事务,即恢复到系统默认设置
autocommit = 1
-- 事务结束
SET autocommit = 1; -- 开启自动提交(系统默认设置)
综上:
-- 手动处理事务
-- 1.
SET autocommit = 0; -- 关闭自动提交
-- 2.
-- 事务开启
START TRANSACTION; -- 标记一个事务的开始,从这个之后的sql都在同一个事务内
-- 3.
INSERT XX
INSERT XX
-- 4.
-- 回滚 : 只要没COMMIT,就还可以滚回到的原来的样子
ROLLBACK;
-- 提交 : 持久化(一旦提交,再回滚也滚不回去了)
COMMIT;
--5.
-- 事务结束
SET autocommit = 1; -- 开启自动提交
-- 补充:(了解)
SAVEPOINT 保存点名 -- 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点
示例:(
转账实现
)
-- 创建数据库:
CREATE DATABASE `shop` CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 创建数据表:
CREATE TABLE `account` (
`id` INT(4) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(10,2) NOT NULL, -- VARCHAR(30)
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 插入数据
INSERT INTO `account`
VALUES(12,'小王',1000),(16,'小张',800)
-- 执行事务:
-- 1.关闭自动提交
SET autocommit = 0
-- 2.开启事务
START TRANSACTION
-- 3.一组sql(虽然是一组sql,但也要挨个单句执行,多句执行应该可以,但现在是初学阶段)
UPDATE `account` SET `money` = `money` - 20 WHERE `name`='小王'
UPDATE `account` SET `money` = `money` + 20 WHERE `name`='小张'
-- 4.只要没COMMIT,就可以回滚;一旦提交,再回滚也滚不回去了
ROLLBACK
COMMIT
-- 5.恢复系统的默认设置
SET autocommit = 1
结果:
执行事务之前:
执行事务之后:
(只要没执行COMMIT,通过执行ROLLBACK是可以回到上上张图片的;一旦执行COMMIT,信息就永久更新,不可逆)
注意:(在实际应用中)
上面的示例只是
手动
去处理事务,在实际应用中,会把上面示例中的第3步和第4步放在一个
try...catch...
中,如果要执行的一组sql没有问题,能成功运行,就自动COMMIT,如果运行失败,相当于是异常情况,就跳到catch中自动回滚。
七、索引(index)
30,31小结
30主要讲了以下内容:
- 啥是索引:是一种数据结构,用它可以快速找到数据。
-
索引的
分类
:主键索引(只能有一个)、唯一索引、常规索引、全文索引。 -
添加索引
的三种方式:1.创建数据表的时候;2.用ALTER创建;3.用CREATE创建。 -
删除索引
:
DROP INDEX 索引名 ON 表名字;
-
查看所有索引
:
SHOW INDEX FROM 表名;
-
然后用
全文索引
写了个例子,来
说明有索引和没索引的区别
:没索引就是整个数据表去搜索,有索引就是直接一下子找到。
这里面用了关键字
EXPLAIN
来
查看sql执行的状况
,相当于是个工具,可以查看这次查询
一共用了多久的时间,查找了多少行数据
。
31中又写了一个例子,依然是
全文索引
:
-
把数据量增加到
100万条
; -
用了一个函数
mock_data()
,先把这个函数写好; -
然后执行这个函数
SELECT mock_data();
-
然后又借助关键字
EXPLAIN
来说明加索引和不加索引的区别:不加索引,查一条数据要用
1s
多,加上索引再查这条数据只用
0.01s
。
结论:
索引在小数据量的时候,用处不大,但是在大数据的时候,优势十分明显
。
30.索引的 介绍、分类、添加、示例
索引的定义:
-
索引(index)是帮助MySQL
高效获取数据
的
数据结构
。
索引的本质:
-
索引是数据结构
。
索引的作用:
-
提高查询速度
; - 确保数据的唯一性;
- 可以加速表和表之间的连接 , 实现表与表之间的参照完整性;
- 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间;
- 全文检索字段进行搜索优化。
索引的分类:
-
主键索引(
primary key
):
唯一的标识,主键的内容不可重复,且只能有一个列(字段)作为主键。 -
唯一索引(
unique key
):
避免出现重复的列名(字段名)
,可以有多个唯一索引,即可以将
多个列
标识为唯一索引。 -
常规索引(
key / index
):
默认的index 或者 key 关键字 -
全文索引(
FullText index
):
在特定的数据库引擎下才有,如
MYISAM
;
可以快速定位数据。
注意:
主键索引只能有一个;唯一索引可以有多个。
添加所有的三种方式:
参考链接:
数据库创建索引和删除索引的方式总结
1.创建表时给字段增加索引
-- 格式:
CREATE TABLE 表名 (
字段名1 数据类型 [完整性约束条件…],
字段名2 数据类型 [完整性约束条件…],
[UNIQUE | FULLTEXT | PRIMARY] INDEX/KEY
[索引名] (字段名)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 示例:
CREATE TABLE `result`(
-- 省略一些代码
PRIMARY KEY (`student_name`), -- 主键索引
INDEX/KEY `ind` (`studentNo`,`subjectNo`), -- 常规索引
UNIQUE KEY `UK_IDENTITY_CARD` (`identity_card`), -- 唯一索引
FULLTEXT INDEX `FI_PHONE` (`phone`) -- 全文索引
)ENGINE=INNODB DEFAULT CHARSET=utf8
注意:
因为主键索引是唯一的,所以不需要索引名,直接在括号里写字段名即可。
2.用ALTER在已建好的表上创建索引
-- 格式:
ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | ] INDEX/KEY
索引名 (字段名)
-- 示例:
ALTER TABLE `student` ADD PRIMARY KEY (`student_name`); -- 主键索引
ALTER TABLE `result` ADD INDEX `ind`(`studentNo`,`subjectNo`); -- 常规索引
ALTER TABLE `student` ADD UNIQUE KEY `UK_IDENTITY_CARD` (`identity_card`); -- 唯一索引
ALTER TABLE `student` ADD FULLTEXT INDEX `FI_PHONE` (`phone`); -- 全文索引
3.用CREATE在已建好的表上创建索引
语法:
create index 索引名 on 表名(字段)
-- 格式:
CREATE [UNIQUE | FULLTEXT ] INDEX
索引名 ON 表名 (字段名)
-- 示例:
CREATE INDEX `name` ON `student` (`studentname`);
注意:
Create不能用于创建Primary key索引
其他操作:(
删除索引、显示索引信息
)
-- 删除索引:
DROP INDEX 索引名 ON 表名字;
DROP INDEX `name` ON `student` -- 示例
-- 删除主键索引:
ALTER TABLE 表名 DROP PRIMARY KEY;
ALTER TABLE 表名 DROP INDEX 索引名;
-- 显示索引信息:
SHOW INDEX FROM 表名;
一个完整的示例:
-- 显示所有的索引信息:
SHOW INDEX FROM `student`
-- 创建一个索引:
CREATE INDEX `name` ON `student` (`studentname`)
-- 删除索引:
DROP INDEX `name` ON `student`
-- 用explain来查看sql执行的状况,相当于是个工具,可以查看这次查询一共用了多久的时间,查找了多少行数据
-- 非全文索引:
SELECT * FROM `student` WHERE `studentname`='张伟强'
EXPLAIN SELECT * FROM `student` WHERE `studentname`='张伟强'
-- 增加全文索引:
ALTER TABLE `student` ADD FULLTEXT INDEX `name`(`studentname`);
-- 全文索引:
SELECT * FROM `student` WHERE `studentname`='张伟强'
EXPLAIN SELECT * FROM `student` WHERE MATCH(`studentname`) AGAINST('张伟强');
示例所用到的数据表:
结果:
查看所有索引:
非全文索引:
添加全文索引:
全文索引:
解释下上面的
全文索引
:
– 全文搜索通过
MATCH()
函数完成。
– 搜索字符串作为
against()
的参数被给定。搜索以忽略字母大小写的方式执行。对于表中的每个记录行,MATCH() 返回一个相关性值。即,在搜索字符串与记录行在 MATCH() 列表中指定的列的文本之间的相似性尺度。
-- 示例:
EXPLAIN SELECT *FROM student WHERE MATCH(studentname) AGAINST('love');
补充:
全文索引的版本、存储引擎、数据类型的支持情况:
-
MySQL 5.6 以前的版本,
只有 MyISAM 存储引擎支持全文索引
; -
MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎
均支持
全文索引; - 只有字段的数据类型为 char、varchar、text 及其系列才可以创建全文索引;
- 测试或使用全文索引时,要先看一下自己的 MySQL 版本、存储引擎和数据类型是否支持全文索引。
参考链接:
【MySQL优化】——
看懂explain_漫漫长途,终有回转;余味苦涩,终有回甘-CSDN博客_explain
31. SQL编程创建100万条数据测试索引
1.建表app_user:
CREATE TABLE app_user (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` VARCHAR(50) DEFAULT '' COMMENT '用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男 1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'
2.批量插入100w条数据:(
mock_data()
是个函数)
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('用户',i),'123345@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i = i+1;
END WHILE;
RETURN i;
END;
-- 执行函数
SELECT mock_data();
-- 查表
SELECT * FROM app_user;
3.测试:
-- 测试:
-- 查看索引信息:
SHOW INDEX FROM `app_user`
-- 删除索引:
DROP INDEX id_app_user_name ON `app_user`
SELECT * FROM app_user WHERE `name` = '用户9999'; -- 1.260 sec
EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.002 sec
-- 创建索引:
-- id_表名_字段名 索引名
-- CREATE INDEX 索引名 ON 表名(`字段名`);
CREATE INDEX id_app_user_name ON app_user(`name`);
SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.001 sec
EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999'; -- 0.001 sec
结果:
不加索引:
加索引:
查看索引信息:
结论:
索引在小数据量的时候,用处不大,但是在大数据的时候,区分十分明显。
32. 索引的 原则、数据结构
索引的原则:
- 索引不是越多越好;
- 不要对经常变动的数据加索引;
- 小数据量的表建议不要加索引;
- 索引一般应加在查找条件的字段。
索引的数据结构:
1.Hash类型的索引;
2.BTree(B树):INNODB引擎默认的数据结构;
3.全文索引。
– 我们可以在创建上述索引的时候,为其指定索引类型,分两类
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)
– 不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;
参考链接:
MySQL索引背后的数据结构及算法原理
32’ 补充1: BTree索引(32中参考链接的内容)
摘要:
MySQL数据库支持多种索引类型,如
BTree索引,哈希索引,全文索引
等等。
为了避免混乱,本文将只关注于BTree索引,因为这是平常
使用MySQL时主要打交道的索引
,至于哈希索引和全文索引本文暂不讨论。
第一部分:数据机构及算法基础
数据库查询
是数据库的最主要功能之一,我们都希望查询数据的速度能
尽可能的快
。
常见的查询算法有
-
顺序查找(linear search):这种复杂度为
O(n)
的算法在数据量很大时显然是糟糕的。 -
二分查找(binary search):二分查找
要求被检索数据有序
; -
二叉树查找(binary tree search):二叉树查找
只能应用于二叉查找树上
;
二叉查找树的改进:平衡二叉树(AVL树)+ 红黑树 –>见下面的
8.3 基于 树 的查找法 补充:红黑树和AVL树的详解和区别
在实际的数据库系统几乎没有使用二叉查找树或其进化品种红黑树(red-black tree)实现,因为数据本身的组织结构不可能完全满足各种数据结构(例如,理论上不可能同时将两列都按顺序进行组织)。所以在数据之外,
数据库系统还维护着满足特定查找算法的数据结构
,这些数据结构
以某种方式引用(指向)数据
,这样就可以在这些数据结构上
实现高级查找算法
,这种数据结构就是
索引(index)
。
目前大部分数据库系统及文件系统都采用
B-Tree
或其变种
B+Tree
作为索引结构。
B树
:(1)–>(2)–>(3)
(1)二叉排序树,又叫二叉查找树:
-
若左子树为空,则
左子树
上所有结点的值均
小于
根结点的值;
若右子树为空,则
右子树上
所有结点的值均
大于等于
根结点的值;
左右子树也分别为二叉排序树。 -
中序遍历
一个二叉排序树可以得到一个
递增有序序列
。
(2)m叉排序树,又叫m路查找树:
-
一个结点最多有
m
棵子树,
m-1
个关键字; -
子树
Pi
中的所有关键字均大于
Ki
,小于
K(i+1)
; -
子树
P0
中的关键字均小于
K1
,子树
Pn
中的所有关键字均大于
Kn
; - 子树Pi也是m路查找树
-
书本P289的
例8.7
-
(3)B树,一颗
平衡
的m路查找树: -
每个结点做多有
m
棵子树; -
根结点至少有
2
棵子树; -
除根结点之外的所有非叶结点至少有
ceiling(m/2)
棵子树,
ceiling(m/2) - 1
个关键字; - 所有叶结点在同一层,也叫失败结点;
-
B树是“从叶向根”生长的,而根对每个分支是公用的,所以不论根长到多“深”,各分支的长度同步增长,
因而各分支是“平衡”的
; -
书中P289的
例8.8、8.9
,—B树的基本性质
P293的
例8.10,8.11
,—B树中插入一个关键字
P296的
例8.12,8.13
,—B树中删除一个关键字
**
B树
**有许多变种,其中最常见的是
B+Tree
,例如MySQL就普遍使用
B+Tree
实现其索引结构。那么B树和B+树区别在哪?
参考链接1:
简单剖析B树(B-Tree)与B+树
常说的B-树就是B树,没有所谓的B减树。
聚集索引(Clustered Index)、非聚集索引(NonClustered Index)、卫星数据?
B+树相比B树的优势:
1.单一节点存储更多的元素,使得查询的IO次数更少;
2.所有查询都要查找到叶子节点,查询性能稳定;
3.所有叶子节点形成有序链表,便于范围查询。
参考链接2:
B树和B+树
不同数据库引擎(MYISAM引擎和INNODB引擎)中B+树的差异:。
参考链接3:
B树与B+树简明扼要的区别
参考链接4:
面试总结:B树,B+树的原理及区别
参考链接5:
面试题:B(B-)树,B+树,B树和B+树的区别,B树和B+树的优点
参考链接6:
B树、B-树、B+树、B*树之间的关系
第二部分:MySQL索引实现:
- MyISAM索引实现
- InnoDB索引实现
第三部分:索引使用策略及优化
32’’ 补充2:数据结构教材的 第八章 查找算法
8.2 基于 线性表 的查找法
- 顺序查找法:
- 折半查找法:顺序存储、数据有序
-
分块查找法:创建一个索引表,每个索引项记录一个块的
起始位置
和块中的
最大关键字
,索引表按关键字有序排列(即块之间有序,块内无序)。先用顺序查找或折半查找
锁定块
,然后在块内用顺序查找法。
8.3 基于 树 的查找法
-
二叉排序树:(二叉查找树)
若左子树为空,则
左子树
上所有结点的值均
小于
根结点的值;
若右子树为空,则
右子树上
所有结点的值均
大于等于
根结点的值;
左右子树也分别为二叉排序树。
中序遍历
一个二叉排序树可以得到一个
递增有序序列
。 -
平衡二叉排序树:(AVL树)
左右子树的
高度之差的绝对值小于等于1
;左右子树也是平衡二叉排序树。
结点的
平衡因子
(Balance Factor)是指结点的左右子树深度之差,AVL树中所有结点的平衡因子只能是-1、0、1。
给一个AVL树上插入一个结点,可能导致树失衡,失衡类型及相应的调整方法可归纳为四种:
LL型、LR型、RR型、RL型
。
红黑树和AVL树的区别:(见下面的详解) -
B树:
见
教材的P288 – P298
,或者直接看上面的
32’ 补充1:BTree索引
补充:红黑树和AVL树的详解和区别
(参考链接:
红黑树和AVL树(平衡二叉树)区别
、
链接2
)
AVL树是严格的平衡二叉树,一旦失衡就要通过
旋转
来保持平衡,而
旋转是非常耗时的
,因此AVL树适合用于
插入与删除次数比较少,但查找比较多
的情况。由于维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而
实际的应用不多
,更多的地方是用
追求局部而不是非常严格整体平衡
的
红黑树
。当然,如果应用场景中对
插入、删除不频繁
,只是
对查找要求较高
,那么AVL还是较优于红黑树。
红黑树是一种
二叉查找树
,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(
非红即黑
)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,
红黑树确保没有一条路径会比其它路径长出两倍
,因此,红黑树是一种
弱平衡二叉树
(由于是弱平衡,可以看到,在相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,
红黑树的旋转次数少
,
插入,删除,查找的复杂度都是O(log N)
,所以
对于搜索,插入,删除操作较多的情况下,就用红黑树。
。
红黑树的规则:
-
规则1: 每个节点不是黑色就是红色(
非红即黑
); -
规则2:
根节点为黑色
; -
规则3
:红色节点的父节点和子节点不能为红色;
红色结点的两儿子都是黑的
-
规则4:所有的
叶子节点都是黑色
(空节点视为叶子节点NIL); -
规则5
:
任意一个节点
到叶子节点的
每条路径上
黑色节点的个数都相等; -
规则6(特点):
从根节点到叶子节点的最长的路径不多于最短的路径的长度的两倍
。
红黑树插入节点时的思路:(参考链接:
红黑树与平衡二叉树区别?
)
插入的节点总是设为红节点,当其复节点为红节点时,这就有破坏了规则3,就需要调整。将插入节点作为考察节点,考察其叔父,如果也是红节点,则将其父亲和叔父改为黑节点,而将其祖父改为红节点,然后以其祖父为考察节点。如果其叔父是黑节点则做一旋转变换可以搞定,没有图不太好说明,你可以自己考虑一下,总之它的思想是把“多出来”的红色往上一层推去,确保下面层红黑性质,最后推到根以后,如果依然违反性质1,则可以直接把根由红改黑即可,就相当于把这“多出来”的红色推到树以外的节点去了。
删除节点时先要找到顶替的节点,如果删去的节点是黑色则破坏了规则5,也需要调整。调整的思想也同前面类似,把这个黑色赋予顶替节点,则顶替节点相当于有两重黑色,然后将它的两重黑色向上推,一直推到根,再从根推到外面去了。
平衡二叉树和红黑树的区别:
AVL树 | 红黑树 | |
---|---|---|
概念 | 严格的平衡二叉树,左右子树高度差的绝对值≤1 |
弱平衡树,见上面的: 红黑树的规则 |
失衡类型及相应的调整方法 |
|
见上面的 红黑树插入节点时的思路 |
插入、删除 | 因为要通过旋转来恢复平衡,代价高 | O(log N) |
查找 | O(log N) | O(log N) |
应用 |
适合用于插入与删除次数比较少,但查找比较多的情况 如果应用场景中对 插入、删除不频繁 ,只是 对查找要求较高 ,那么AVL还是较优于红黑树。 |
对于查找,插入,删除操作较多的情况下,就用红黑树; 广泛用于C++的STL中,map和set都是用红黑树实现的 |
左右自述的高度差绝对值 | 小于等于1 |
某些时刻可能会超过1,但 红黑树确保没有一条路径会比其它路径长出两倍 ,只要符合红黑树的规则即可 |
失衡后的具体操作 | 只要不平衡就会进行旋转 | 改变颜色+旋转 |
是否是高度平衡 | 是,严格的平衡二叉树 | 否,弱平衡的二叉树,插入最多两次旋转,删除最多三次旋转 |
多余的内容:(不用看)
平衡二叉树和红黑树的区别:
+ 平衡二叉树的左右子树的高度差绝对值不超过1,
但是红黑树在某些时刻可能会超过1,**红黑树确保没有一条路径会比其它路径长出两倍**,只要符合红黑树的五个条件即可;
+ 二叉树**只要不平衡就会进行旋转**,
而红黑树不符合规则时,**有些情况只用改变颜色不用旋转,就能达到平衡**;
+ AVL树适合用于**插入与删除次数比较少,但查找比较多**的情况,
对于**搜索,插入,删除操作较多的情况**下,就用**红黑树**;
+ AVL 树是**高度平衡的**,频繁的插入和删除,会引起频繁的reblance,导致效率下降,
红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。
8.4 计算式查找法(哈希表)
八、权限管理和备份
33. 数据库用户管理
方式一:用
SQLyog可视化
管理用户
- 添加用户;
- 删除用户;
- 管理用户权限(全局权限、对某个数据库的权限、对某个数据表的权限)
方式二:用
sql命令
管理用户
(首先找到用户表,在mysql数据库–>user数据表中)
用
sql命令
对用户进行管理,实质上就是
对用户表进行增删改查
。
创建用户、修改密码、重命名、用户授权、查看权限、撤销权限、删除用户
-- 创建用户:
-- 格式:CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER lele IDENTIFIED BY '123456'
CREATE USER 'user_name'@'192.168.1.1' IDENTIFIED BY '123456'
-- 修改密码(修改当前用户密码):当前用户是root
SET PASSWORD = PASSWORD('654321'); -- 记得把密码改回来('123456')
-- 修改密码(修改指定用户密码):
SET PASSWORD FOR lele = PASSWORD('654321'); -- 记得把密码改回来('123456')
-- 修改密码:(数据库笔记1中的两条修改密码的命令行)
UPDATE mysql.user SET authentication_string=PASSWORD('123456') WHERE USER='root' AND HOST = 'localhost';
UPDATE USER SET PASSWORD=PASSWORD('123456')WHERE USER='root'; 修改密码
-- 重命名:
-- 格式:RENAME USER 原名字 TO 新名字;
RENAME USER lele TO lele2
-- 用户授权:
-- 格式:GRANT 权限列表 ON 数据库名.数据表名 TO 用户名
-- 给 用户lele2 授予 所有的库的所有的表 全部的权限ALL PRIVILEGES,
GRANT ALL PRIVILEGES ON *.* TO lele2
-- (解释:*.* 表示所有库的所有表; 库名.表名 表示某库下面的某表
-- 这里的 ALL PRIVILEGES 是除了给别人授权不行,其他都能干,
-- 即ALL PRIVILEGES指除了GRANT权限之外的所有权限)
-- 查看权限:
-- 查看当前用户的权限:
SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();
-- 查看用户lele2的权限:(除GRANT权限之外的ALL PRIVILEGES)
SHOW GRANTS FOR lele2
-- 结果:GRANT ALL PRIVILEGES ON *.* TO 'lele2'@'%'
-- 查看root的权限:(有GRANT权限,和ALL PRIVILEGES)
SHOW GRANTS FOR root@localhost
-- 结果:GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
-- 撤销权限:(和授予权限正好相反)
-- 格式:REVOKE 权限列表 ON 数据库名.数据表名 FROM 用户名
REVOKE ALL PRIVILEGES ON *.* FROM lele2 --撤销用户lele2的所有权限
-- REVOKE ALL PRIVILEGES, GRANT OPTION FROM root -- 撤销root的所有权限
-- 不建议这么干!!!
-- 删除用户:
DROP USER lele2
授予权限的结果:
授予权限之前:
授予权限之后:(
GRANT ALL PRIVILEGES ON *.* TO lele2
)
权限解释:
-- 权限列表
ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限
ALTER -- 允许使用ALTER TABLE
ALTER ROUTINE -- 更改或取消已存储的子程序
CREATE -- 允许使用CREATE TABLE
CREATE ROUTINE -- 创建已存储的子程序
CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLE
CREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
CREATE VIEW -- 允许使用CREATE VIEW
DELETE -- 允许使用DELETE
DROP -- 允许使用DROP TABLE
EXECUTE -- 允许用户运行已存储的子程序
FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE
INDEX -- 允许使用CREATE INDEX和DROP INDEX
INSERT -- 允许使用INSERT
LOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLES
PROCESS -- 允许使用SHOW FULL PROCESSLIST
REFERENCES -- 未被实施
RELOAD -- 允许使用FLUSH
REPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址
REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)
SELECT -- 允许使用SELECT
SHOW DATABASES -- 显示所有数据库
SHOW VIEW -- 允许使用SHOW CREATE VIEW
SHUTDOWN -- 允许使用mysqladmin shutdown
SUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。
UPDATE -- 允许使用UPDATE
USAGE -- “无权限”的同义词
GRANT OPTION -- 允许授予权限
/* 表维护 */
-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
34. MySQL备份
为什么要备份?
- 保证重要的数据不丢失;
- 数据转移。
MySQL数据库备份方法(三种方法)
-
1.直接拷贝数据库文件和相关配置文件; –
data
文件夹(数据库笔记1中有提及) -
2.在
sqlyog
这种可视化工具中手动导出;– 可视化操作 -
3.使用命令行
mysqldump
导出 。 – 命令行
在sqlyog这种可视化工具中手动导出
在想要导出的表或者库中,右键:
注意下图中三处框起来的地方即可:
使用命令行
mysqldump
导出
mysqldump
导出:
-- 导出一张表 :
-- 格式:mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
-- 导出多张表 :
-- 格式:mysqldump -h主机 -u用户名 -p密码 数据库 表名1 表名2 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school student result >D:/b.sql
-- 导出整个数据库 :
-- 格式:mysqldump -h主机 -u用户名 -p密码 数据库 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school >D:/c.sql
导入:
方式一:(推荐)
-
先
登录
; -
切换到
指定的数据库
; -
然后
source 备份文件
。
(测试的时候可以先把school库中的student表备份下来a.sql,然后把student表删掉,然后按照上面的三个步骤导入)
方式二:(不推荐)
也可以这样:
mysql -u用户名 -p密码 库名 < 备份文件(要导入的文件)
九、规范数据库设计
35. 如何设计一个项目的数据库
为什么需要设计?
当数据库比较复杂的时候
,我们就需要设计了。
糟糕的数据库设计:
- 数据冗余,浪费空间;
- 数据库插入和删除都会麻烦、异常(屏蔽使用物理外键);
- 程序的性能差。
良好的数据库设计:
- 节省内存空间;
- 保证数据库的完整性;
- 方便我们开发系统。
软件项目开发周期中数据库设计:
- 需求分析阶段: 分析客户的业务和数据处理需求
- 概要设计阶段:设计数据库的E-R模型图 , 确认需求信息的正确和完整.
设计数据库步骤:(个人博客)
第1步:
收集信息
(与该系统有关人员进行交流 , 座谈 , 充分了解用户需求 , 理解数据库需要完成的任务)
- 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
- 分类表(文章分类,谁创建的)
- 文章表(文章信息)
- 评论表
- 友链表(友情链接信息)
- 自定义表(系统信息,某个关键的字,或者一些主字段) key:value
- 关注表(粉丝数)
- 说说表(发表心情,字段: id…content…create_time)
第2步:
标识实体
[Entity]
(把需求落地到每个字段,数据库要管理的关键对象或实体,实体一般是名词,标识每个实体需要存储的详细信息[Attribute])
-
用户表:
-
分类表:
-
文章表:
-
评论表:
- 友链表:
-
关注表:
第3步:
标识实体之间的关系
[Relationship]
- 写博客:user –> blog
- 创建分类:user –> category
- 关注:user –> user
- 友链:links
- 评论:user –> user –> blog
博客,bbs,Ant Design
36.数据库的三大范式(了解)
问题 : 为什么需要数据规范化?
不合规范的表设计会导致的问题:
- 信息重复;
- 更新异常;
- 插入异常:无法正确表示信息;
- 删除异常:丢失有效信息。
三大范式:
第一范式 (1st NF):
-
原子性:保证
每一列不可再分
;
第二范式(2nd NF):
- 前提:满足第一范式
-
每张表只描述一件事情
;
第三范式(3rd NF):
- 前提:满足第一范式和第二范式
-
第三范式需要确保数据表中的每一列数据都
和主键直接相关,而不能间接相关
。
三大范式是用来规范数据库的设计,但存在规范性和性能的问题(不可兼得的关系):
(阿里有句话:
关联查询的表不得超过三张表
)
-
考虑
商业化的需求和目标
(成本,用户体验)时,数据库的
性能更加重要
; -
在规范性能的问题的时候,需要
综合考虑
一下规范性; -
有时会故意给某些表增加一些
冗余的字段
(从多表查询中变为单表查询),以大量减少需要从中搜索信息所需的时间; -
有时会故意增加一些
计算列
(从大数据库降低为小数据量的查询:索引)。
十、JDBC(重点)
37. 数据库驱动 和 JDBC
1.数据库驱动
驱动:声卡、显卡、数据库
应用程序
通过
数据库驱动
和
数据库
打交道。
2.JDBC
UN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称
JDBC
。
这些规范的实现由具体的厂商去做~
对于开发人员来说,我们
只需要掌握JDBC接口的操作
即可!
38-44
45. 数据库连接池
数据库连接 – 执行完毕 – 释放
整个过程中
连接– 释放
是十分浪费系统资源的,所以就有了
池化技术
:准备一些预先的资源,过来就连接预先准备好的。
最小连接数
:10(常用连接数)
最大连接数
:100 (业务最高承载上线)
等待超时
:100ms(等待超过100ms就会告诉客户这里发生异常,让客户找别家)
编写连接池,实现一个接口DataSource。
总结:无论用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变。
(数据库的课先学到这,2022-04-15 21:44:26)