数据库的高级特性和新方法
- 数据库的高级操作
- 数据库事务
- 用户权限控制
- 数据的备份与还原
- Binlog运行日志
- 数据库的新特性
- 窗口函数的使用
阅读指南:
本文探讨了数据库的高级特性和新方法,详细介绍了这些高级特性及其操作方式,并涵盖了一些最新的操作方法。如果读者感兴趣,我们将会在后续的数据库教程合集里更新更多高级操作内容,欢迎大家与我们一起学习和讨论。这篇文章是本系列的最后一篇,感谢大家的阅读和支持。
合集链接:
数据库详细基础教程
数据库的高级操作
数据库事务
数据库事务概述:
-
数据库事务是一套操作数据命令的有序集合,一个不可分割的工作单位。
-
事务中单个命令不会立刻改变数据库数据,当内部全部的命令都生效且成功时,才算一次成功,如果有任一任务失败,可以进行状态回滚
-
事务哟事务开始与事务结束之间执行的全部数据库操作组成
事务的作用:
- 为数据库提供了一个从失败中恢复到正常状态的方法
- 当对个应用程序在并发访问数据库时,可以有效避免彼此的操作互相干扰
♦️事务的ACID特性:
- 原子性(Automicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency)
一致性是指事务内部的操作的状态前后一致,即成功则都成功,失败则都失败。
- 隔离性(Isolation)
隔离性是指一个事物的执行不能被其他事物干扰,即一个事物内部的操作即使用的数据对并发的其他事务是隔离的,并发实现的各个事务之间都不能相互干扰。
- 持久性(Durability)
持久性是指一个事物一旦被提交,他对数据库中数据的改变就是永久性的,后面的操作对其不成影响。
事务的开启,提交,回滚:
前提:
MySQL默认情况下是自动提交事务的。
默认每一条语句都是一个独立的事务,一旦成功就提交了。语句失败报错就回滚。
那要将多条语句作为一个事物,有如下方法
方法一:手动提交模式
# 开启手动提交模式,这个模式的生命周期只在一次服务时间内,也就是说,如果关闭了sql服务,则再次打开时需要再一次开启,最好在终端进行操作
SET AUTOCOMMIT = FALSE;
或
SET AUTOCOMMIT = 0;# 恢复自动提交
SET AUTOCOMMIT = TRUE;
或
SET AUTOCOMMIT = 1;# 查看是否自动提交
SHOW VARIABLES LIKE 'AUTOCOMMIT';# 成功 —> 提交,失败 -> 回滚COMMIT; ROLLBACK;
方法二: 自动提交模式下开启独立事务
START TRANSACTION; # 开启独立事务.......... # 多个sql命令COMMIT; 或 ROLLBACK;
注:
事务只支持在update,insert,delete这类对数据产生变化的方法中,不支持删表,删库那种操作。
事务的隔离性:
一个书屋内部的操作即使用的数据对并发的其他事物是隔离的,并发执行的各事务之间不能相互干扰
隔离级别 | 概述 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
read-uncommitted | 读未提交事务数据 | √ | √ | √ |
read-committed | 读已提交事务数据(orcle默认) | × | √ | √ |
repeatable-read | 可重复度(MySQL默认) | × | × | √(小概率) |
aseializable | 串行化和序列化 | × | × | × |
脏读:一个事务读取了另一个事务未提交的数据
不可重复读取:一个事务读取了另一个事务所提交的修改数据,不符合数据的一致性
幻读:一个事务读取了另一个事务新增,删除的记录情况,与实际情况不同。
# 改变隔离级别
SET TRANSACTION_ISOLATION = '隔离级别';# 查看隔离级别
SELEC T@@TRANSACTION_ISOLATION;
注:
隔离等级越高,越安全,但是性能越低。
用户权限控制
授予的权限可分为三个级别:数据库级别,表级别或特定操作上。
创建用户语法:
CREATE USER 'username' @ '服务器ip地址(%代表所有ip)' IDENTIFIED BY 'password';
# username 表示要创建的用户的用户名
# password 表示创建的用户的用户名
赋予权限语法:
# 1. 赋予全部权限
GRANT ALL PRIVIEGES ON 库名(*代表全部).表名(*代表全部) TO 'username' @ '服务器ip地址(%代表所有ip)';
# 2.指定库和权限
GRANT SELECT, INSERT ON 库名.表名 TO 'username' @ '服务器ip地址(%代表所有ip)';
回收权限语法:
# 撤销全部权限
REMOVE ALL PRIVILEGES ON database_name.* FROM 'username' @ 'IP';
# 撤销部分权限
REMOVE SELECT, INSERT,UPDATE ON database_name.table_name FROM 'username' @ 'IP';
查看权限语法:
# 查看权限
SHOW GRANTS FOR 'username' @ 'IP';# 查看有用户列表
SELECT User, Host FROM mysql.user;
删除用户语法:
# 删除用户
DROP USER '用户名';
数据的备份与还原
全量备份
# 备份单库和单表的数据
mysqldump -u username -p database_name 表名>backup.sql# 备份单库和多表
mysqldump -u username -p database_name 表名1 表名2...>backup.sql# 备份单库的所有表
mysqldump -u username -p database_name > backup.sql#-p如果写密码,必须紧贴着
# 以上命令必须在未连mysql的状态下执行(CMD执行)
全量恢复
# 还原数据
mysql -u username -p database_name < backup.sql# 需要提前准备数据库,导入已存在的数据库,同时,数据库的MySQ版本要兼容
Binlog运行日志
Binlog日志是一个MySQL的二进制的日志记录,里面记录了数据库所有的增删改查的操作,同时也包括了操作的执行时间,所以,我们可以通过该日志查询误删除数据的恢复,增量复制,主从同步等。
Binlog配置文件的地址
默认在:MySQL服务/my.ini
其中有一部分是
[mysqld]
……
datadir = MySQL服务/Data # 默认的存储详细Binlog的二进制文件地址
……
log-bin = Binlog的文件名 # 此处Binlog的文件名默认是以电脑名称命名,可以修改
对日志的操作(以下操作在 SQLyog 中使用):
示例:
# 清空原有日志文件
RESET MASTER;# 准备数据,插入数据 --> 00000001日志文件
CREATE DATABASE text_binlog;
USE text_binlog;
CREATE TABLE table_binlog(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20) NOT NULL
);
INSERT INTO table_binlog (NAME) VALUES ('二狗子'),('驴蛋蛋');# 重启一个新的日志文件 --> 00000002日志文件
FLUSH LOGS; # 创建一个新日志# 将删除数据和插入数据植入到第二个日志文件中-->00000002日志文件
DELETE FROM table_binlog WHERE id = 2; # 删除驴蛋蛋
INSERT INTO table_binlog(NAME) VALUES('狗剩子');
SELEC *FROM table_binlog;# 查看日志文件目录
SHOW BINARY LOGS;# 查兰某个日志的命令清单
# 语法:
SHOW BINARY EVENTS; 查看第一个日志的清单
SHOW BINARY EVENTS IN '清单名' [FROM pos(具体信息位置) LIMIT OFSET, NUMBER]0;
# 实例:
SHOW BINARY EVENTS IN 'MY_LOGIN.00000002' FROM 391 LIMIT 1, 3;
CMD下的日志操作:
注:在binlog的文件目录下进行cmd
# 跳过步骤找回数据
mysqlbinlog my-logbin.000001> d:/my_binlog.000001.sql # 将其他的日志完整导出
mysqlbinlog --stop-POSITION=删除命令的开始的pos my-logbin.000002> d:/my_binlog.391.sql # 02日志删除之前
mysqlbinlog --start-POSITION=删除命令的下一个命令开始pos my-logbin.000002> d:/my_binlog.441.sql # 02日志删除之后
数据库的新特性
窗口函数的使用
窗口函数:
-
序号函数: row_number()
-
序号函数: rank()
-
序号函数: dense_rank()
-
分步函数: PERCENT_RANK()
(rank - 1) 1 / (rows - 1)
-
前后函数: LAG(expr,n)
LAG(expr,n)函数返回当前行的前n行的expr的值。
-
首尾函数: FIRST_VALUE(expr)
FIRST_VALUE(expr)函数返回第一个expr的值。
示例:
数据的准备
CREATE TABLE goods(id INT PRIMARY KEY AUTO_INCREMENT,category_id INT,category VARCHAR(15),NAME VARCHAR(30),price DECIMAL(10,2),stock INT,upper_time DATETIME
);INSERT INTO goods(category_id,category,NAME,price,stock,upper_time)
VALUES
(1, '女装/女士精品', 'T恤', 39.90, 1000, '2020-11-10 00:00:00'),
(1, '女装/女士精品', '连衣裙', 79.90, 2500, '2020-11-10 00:00:00'),
(1, '女装/女士精品', '卫衣', 89.90, 1500, '2020-11-10 00:00:00'),
(1, '女装/女士精品', '牛仔裤', 89.90, 3500, '2020-11-10 00:00:00'),
(1, '女装/女士精品', '百褶裙', 29.90, 500, '2020-11-10 00:00:00'),
(1, '女装/女士精品', '呢绒外套', 399.90, 1200, '2020-11-10 00:00:00'),
(2, '户外运动', '自行车', 399.90, 1000, '2020-11-10 00:00:00'),
(2, '户外运动', '山地自行车', 1399.90, 2500, '2020-11-10 00:00:00'),
(2, '户外运动', '登山杖', 59.90, 1500, '2020-11-10 00:00:00'),
(2, '户外运动', '骑行装备', 399.90, 3500, '2020-11-10 00:00:00'),
(2, '户外运动', '运动外套', 799.90, 500, '2020-11-10 00:00:00'),
(2, '户外运动', '滑板', 499.90, 1200, '2020-11-10 00:00:00');
使用聚合函数的方式
# 聚合函数也是窗口函数 [理解]
# 查询所有的商品编号,价格,和类别名以及整体平均价格SELECT id , NAME ,price, category , AVG(price) OVER () FROM goods;SELECT id , NAME , price , category , AVG(price) OVER() FROM goods ;# 查询所有的商品编号,价格,和类别名以及类别平均价格
SELECT id , NAME ,price, category , AVG(price) OVER (PARTITION BY category) FROM goods;SELECT id , NAME , price , category , AVG(price) OVER(PARTITION BY category_id) FROM goods ;
使用窗口函数:
# 查询 goods 数据表中每个商品分类下价格降序排列的各个商品信息。
SELECT ROW_NUMBER() OVER(PARTITION BY category ORDER BY price DESC) AS num,id , category , NAME ,price FROM goods;SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num, id,category_id, category, NAME, price, stock FROM goods;
# 窗口函数 over (partition by 分组 order by 排序 )# 查询 goods 数据表中每个商品分类下价格最高的3种商品信息。
SELECT * FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
id, category_id, category, NAME, price, stock FROM goods) tWHERE row_num <= 3;# 使用RANK()函数获取 goods 数据表中各类别的价格从高到低排序的各商品信息。
SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,id, category_id, category, NAME, price, stockFROM goods;# 使用RANK()函数获取 goods 数据表中类别为“女装/女士精品”的价格最高的4款商品信息SELECT * FROM(SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,id, category_id, category, NAME, price, stockFROM goods) tWHERE category_id = 1 AND row_num <= 4;# 使用DENSE_RANK()函数获取 goods 数据表中各类别的价格从高到低排序的各商品信息。
SELECT DENSE_RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock FROM goods;# 使用DENSE_RANK()函数获取 goods 数据表中类别为“女装/女士精品”的价格最高的4款商品信息。
SELECT * FROM( SELECT DENSE_RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock FROM goods) t WHERE category_id = 1 AND row_num <= 3;# 计算 goods 数据表中名称为“女装/女士精品”的类别下的商品的PERCENT_RANK值。
# 写法一:
SELECT RANK() OVER (PARTITION BY category_id ORDER BY price DESC) AS r,PERCENT_RANK()
OVER (PARTITION BY category_id ORDER BY price DESC) AS pr,id, category_id, category,
NAME, price, stock FROM goods WHERE category_id = 1;# 写法二:
SELECT RANK() OVER w AS r,PERCENT_RANK() OVER w AS pr,id, category_id, category, NAME, price, stockFROM goodsWHERE category_id = 1 WINDOW w AS (PARTITION BY category_id ORDER BY price DESC);# 查询goods数据表中前一个商品价格与当前商品价格的差值。
SELECT id, category, NAME, price, pre_price, price - pre_price AS diff_priceFROM (SELECT id, category, NAME, price,LAG(price,1) OVER w AS pre_price FROM goodsWINDOW w AS (PARTITION BY category_id ORDER BY price)) t;# 按照价格排序,查询第1个商品的价格信息。
SELECT id, category, NAME, price, stock,FIRST_VALUE(price) OVER w AS first_priceFROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);