数据库学习笔记2

  • Post author:
  • Post category:其他


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 基于 线性表 的查找法

  • 顺序查找法:
  • 折半查找法:顺序存储、数据有序
  • 分块查找法:创建一个索引表,每个索引项记录一个块的

    起始位置

    和块中的

    最大关键字

    ,索引表按关键字有序排列(即块之间有序,块内无序)。先用顺序查找或折半查找

    锁定块

    ,然后在块内用顺序查找法。

    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 弱平衡树,见上面的:

红黑树的规则
失衡类型及相应的调整方法
LL型、LR型、RR型、RL型
见上面的

红黑树插入节点时的思路
插入、删除 因为要通过旋转来恢复平衡,代价高 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 -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)



版权声明:本文为weixin_38665351原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。