SQL学习-高级特性

256 阅读10分钟

SQL学习-高级特性

本文介绍 MYSQL 语句的高级特性,包括事务处理、使用游标、数据库约束、索引、使用触发器和数据库安全的思考。 供自己以后查漏补缺,也欢迎同道朋友交流学习。

引言

上一篇写了 MYSQL 数据库的高级操作,包含视图、存储过程等,本篇文章将主要介绍 MYSQL 语句的高级特性,包括事务处理、使用游标、数据库约束、索引、使用触发器和数据库安全的思考。

管理事务处理

事务是一组原子性的 SQL 操作,它们要么全部成功,要么全部失败。事务具有 ACID 属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

事务处理是数据库管理系统中的核心功能,它确保数据的完整性一致性。在 MySQL 中,管理事务处理涉及到开启事务、执行事务中的 SQL 语句、提交或回滚事务等操作。

事务的基本操作

  • 开启事务:使用 START TRANSACTION; 或者 BEGIN; 去开启事务。
  • 提交事务:当事务中的所有操作都成功执行后,可以通过 COMMIT; 命令提交事务,使所有更改永久生效。
  • 回滚事务:如果事务中的任何操作失败,或者需要撤销已执行的操作,可以使用 ROLLBACK; 命令回滚事务,撤销所有更改。
-- 开启一个新的事务
START TRANSACTION;

-- 插入一个新的订单
INSERT INTO orders (customer_name, order_date, product_id, quantity)
VALUES ('刘丽', '2024-08-25', 4, 2);

-- 如果更新过程中发生错误
-- ROLLBACK;

-- 提交事务,将更改保存到数据库
COMMIT;

设置隔离级别

支持不同的事务隔离级别,可以通过以下命令设置:

SET SESSION TRANSACTION ISOLATION LEVEL [隔离级别];

隔离级别包括:

  • READ UNCOMMITTED:允许读取未提交的数据。
  • READ COMMITTED:只能读取已提交的数据。
  • REPEATABLE READ:保证在同一事务中多次读取同样的记录结果是一致的
  • SERIALIZABLE最高的隔离级别,完全串行化的事务执行。

使用自动提交

MySQL 默认情况下是自动提交模式,每个单独的 SQL 语句都是一个事务。以下是如何关闭自动提交:

-- 关闭自动提交
SET autocommit = 0;

-- 开启事务
START TRANSACTION;

-- 执行数据库操作
INSERT INTO table_name (column1, column2) VALUES (value1, value2);

-- 提交事务
COMMIT;

-- 或者回滚事务
-- ROLLBACK;

-- 重新开启自动提交
SET autocommit = 1;

处理死锁

如果发生死锁,MySQL 将自动回滚其中一个事务,并抛出异常

-- 开启事务
START TRANSACTION;

-- 尝试执行可能会引起死锁的操作
UPDATE table_name SET column1 = 'value1' WHERE id = 1;
UPDATE table_name SET column1 = 'value2' WHERE id = 2;

-- 如果发生死锁,MySQL将自动回滚其中一个事务,并抛出异常
-- 可以捕获异常并重新尝试事务
COMMIT;

事务中的保存点

在事务中,可以使用保存点(SAVEPOINT)来保存事务的中间状态,以便在需要时回滚(ROLLBACK TO)到特定的保存点。

-- 开启事务
START TRANSACTION;

-- 执行一些数据库操作
INSERT INTO table_name (column1, column2) VALUES (value1, value2);

-- 设置保存点
SAVEPOINT savepoint_name;

-- 执行一些可能会失败的操作
UPDATE table_name SET column1 = value3 WHERE condition;

-- 如果操作失败,回滚到保存点
ROLLBACK TO savepoint_name;

-- 继续执行其他操作
DELETE FROM table_name WHERE condition;

-- 提交事务
COMMIT;

使用游标

游标(Cursor)在数据库中是一种用于逐行处理查询结果集的强大工具,特别适用于需要对结果集中的每一行执行复杂操作的场景。在MySQL 中,游标通常在存储过程中使用。

-- 游标的使用

DELIMITER //

-- 创建存储过程
CREATE PROCEDURE GetProducts()

BEGIN
    -- 声明变量 
    DECLARE done INT DEFAULT FALSE;
    -- 声明变量 产品名称
    DECLARE prd_name VARCHAR(255);
    -- 声明游标
    DECLARE cur CURSOR FOR SELECT product_name FROM products;
    -- 声明游标结束时的处理程序
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    -- 打开游标
    OPEN cur;
    -- 循环读取数据
    read_loop: LOOP
        -- 读取游标数据
        FETCH cur INTO prd_name;
        IF done THEN
          LEAVE read_loop;
        END IF;
        -- 输出产品名称
        SELECT prd_name;
    END LOOP;
    -- 结束循环
    -- 关闭游标
    CLOSE cur;
END //

DELIMITER ;

-- 调用存储过程
CALL GetProducts();

-- 删除存储过程
DROP PROCEDURE GetProducts;
  • 声明游标:在存储过程中,首先需要声明一个游标,为其分配一个查询语句:DECLARE cursor_name CURSOR FOR SELECT_statement;
  • 打开游标:使用 OPEN cursor_name 语句打开游标。
  • 获取游标数据:使用 FETCH cursor_name INTO variables 语句从游标中获取数据。
  • 关闭游标:使用 CLOSE cursor_name 语句关闭游标。

约束

在数据库设计中,约束(Constraints)是用来确保数据库中数据准确性可靠性的一种规则。它们帮助维持数据的完整性,防止无效数据的插入。

主键约束(PRIMARY KEY)

主键约束用于标识表中的每一行,确保每一行数据的唯一性。

ALTER TABLE table_name 
ADD PRIMARY KEY (column_name);

外键约束(FOREIGN KEY)

外键约束用于建立两个表之间的关系,确保引用的数据的完整性。

ALTER TABLE table_name 
ADD CONSTRAINT constraint_name 
FOREIGN KEY (column_name) REFERENCES parent_table(column_name);

唯一约束(UNIQUE)

唯一约束确保列中的值是唯一的。

ALTER TABLE table_name 
ADD UNIQUE (column_name);

非空约束(NOT NULL)

非空约束确保列不能存储 NULL 值。

ALTER TABLE table_name 
MODIFY column_name datatype NOT NULL;

检查约束(CHECK)

检查约束用于限制列中的值必须满足的条件。

ALTER TABLE table_name 
ADD CHECK (column_name condition);

默认值约束(DEFAULT)

默认值约束为列指定一个默认值,如果插入行时没有指定值,则使用默认值。

ALTER TABLE table_name
ALTER COLUMN column_name SET DEFAULT default_value;

级联约束(CASCADE)

级联约束通常与外键约束一起使用,用于定义当主键表中的数据被更新删除时,外键表中相应数据的行为。

CREATE TABLE table_name (
  id INT NOT NULL,
  table2_id INT,
  FOREIGN KEY (table2_id) REFERENCES table_name2(id) ON DELETE CASCADE
);

索引

索引是数据库中用于加速查询排序操作的数据库对象。在 MySQL 中,索引可以显著提高数据检索的效率,尤其是在处理大量数据时。

创建表时创建索引

CREATE TABLE table_name (
  column_name1 DATATYPE,
  column_name2 DATATYPE,
  INDEX index_name (column_name1)
);

为已存在的表添加索引

ALTER TABLE table_name
ADD INDEX index_name (column_name);

删除索引

DROP INDEX index_name ON table_name;

索引类型

索引类型属性描述
普通索引INDEX基本的索引类型,没有唯一性的限制。
唯一索引UNIQUE INDEX确保索引列的值是唯一的。
主键索引PRIMARY KEY既是主键又是索引,唯一且非空。
复合索引COMPOSITE INDEX一个索引包含两个或多个列。
全文索引FULLTEXT INDEX用于全文搜索。
空间索引SPATIAL INDEX用于地理空间数据类型。

索引的维护

定期分析和优化索引,以保持最佳性能。

ANALYZE TABLE table_name;
OPTIMIZE TABLE table_name;

重建索引

对于MyISAM表,可以使用以下命令重建索引:

REPAIR TABLE table_name;

索引的监控

-- 查看表的索引信息:
SHOW INDEXES FROM table_name;

-- 使用 EXPLAIN 关键字查看查询的执行计划,了解索引的使用情况:
EXPLAIN SELECT * FROM table_name WHERE column_name = value;

触发器

触发器(Trigger)是数据库管理系统中的一种特殊的存储过程,它在指定的数据库事件发生时自动执行。

这些事件包括 INSERTUPDATEDELETE 操作。

触发器可以用来执行复杂的业务逻辑数据校验自动更新其他表中的数据等。

触发器的类型

按事件类型分类
  • BEFORE INSERT:在插入操作之前触发。
  • AFTER INSERT:在插入操作之后触发。
  • BEFORE UPDATE:在更新操作之前触发。
  • AFTER UPDATE:在更新操作之后触发。
  • BEFORE DELETE:在删除操作之前触发。
  • AFTER DELETE:在删除操作之后触发。
按操作分类
  • 行级触发器(ROW):针对每一行数据触发。
  • 语句级触发器(STATEMENT):针对整个语句触发。

创建触发器基本语法

CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name
FOR EACH ROW
BEGIN
  -- SQL statements
END;

例如:

DELIMITER //

-- 进行数据校验, 确保库存不能小于100
CREATE TRIGGER validateStock
BEFORE UPDATE 
ON products
FOR EACH ROW
BEGIN
    IF NEW.stock < 100 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = '库存不能为负数';
    END IF;
END //

DELIMITER ;

更新库存:

-- 更新库存
UPDATE products
SET stock = 50
WHERE id = 1;

报错:

sql-trigger-1

触发器的使用场景

  • 自动填充数据:在插入或更新数据时自动填充某些字段。
  • 数据校验:在数据被插入或更新到表中之前进行检查
  • 维护审计日志记录数据的变化历史。
  • 同步更新:在更新一个表时,自动更新另一个相关表。

删除触发器

DROP TRIGGER trigger_name;

触发器使用的注意事项

  • 性能影响:触发器可能会影响数据库操作的性能,尤其是在高并发环境下。
  • 调试困难:触发器的逻辑错误可能难以调试
  • 逻辑复杂性:复杂的业务逻辑应该尽量避免放在触发器中,以保持数据库操作的简单性和可维护性。

数据库安全

数据库安全是确保数据库管理系统(DBMS)及其数据免受恶意攻击、未经授权访问和数据泄露的重要措施。

用户身份验证和授权

用户账户管理
  • 创建用户:为每个数据库操作者创建独立的用户账户。

    CREATE USER 'username'@'host' IDENTIFIED BY 'password';
    
  • 删除用户:不再需要访问数据库的用户应及时删除

    DROP USER 'username'@'host';
    
权限控制
  • 授予权限:仅授予用户完成其工作所必需的最小权限

    GRANT SELECT, INSERT ON database_name.table_name TO 'username'@'host';
    
  • 撤销权限:根据需要撤销不再需要的权限。

    REVOKE SELECT, INSERT ON database_name.table_name FROM 'username'@'host';
    

加密

  • 数据传输加密:使用 SSL 加密数据库客户端和服务器之间的连接。

    CREATE USER 'username'@'host' IDENTIFIED BY 'password' REQUIRE SSL;
    
  • 数据存储加密:对数据库中的数据进行加密,即使数据被非法访问,也无法被读取。

审计和监控

  • 开启审计:配置数据库审计插件,记录所有数据库操作。
  • 分析日志:定期分析审计日志,检测异常行为。
  • 实时监控:使用数据库监控工具监控数据库活动,及时发现可疑行为。

数据备份和恢复

  • 全备份:定期进行数据库全备份
  • 增量备份:进行增量备份,减少数据丢失。
  • 加密备份:对备份文件进行加密,确保备份数据的安全。
  • 异地存储:将备份文件存储在不同的物理位置,以防灾难恢复。
  • 测试恢复:定期测试备份恢复流程,确保在需要时能够快速恢复数据。

应用安全

  • 防止SQL注入:使用参数化查询防止 SQL 注入攻击。
  • 输入验证:在应用层对所有输入数据进行验证,防止恶意数据进入数据库。

网络隔离和防火墙

  • 配置防火墙:使用数据库防火墙来监控和控制进出数据库的流量。
  • DMZ部署:将数据库服务器部署在 DMZ 中,通过防火墙限制访问。

漏洞管理

  • 应用更新补丁:定期更新数据库系统和应用程序,修补已知漏洞。
  • 定期漏洞扫描:使用自动化工具定期扫描数据库系统,发现潜在的安全漏洞。

数据脱敏

  • 数据脱敏:对敏感数据进行脱敏处理,保护个人隐私和遵守法规要求。

SQL学习专栏系列

练习代码库地址

SQL学习 sql-study