软考(软件设计师)数据库原理:事务管理,备份恢复,并发控制

数据库事务管理与备份恢复

事务(Transaction) 是数据库管理系统中执行的一个不可分割的工作单元,它包含一组 SQL 操作,这些操作要么全部成功执行,要么全部不执行。

事务的四大特性(ACID)

  • 原子性(Atomicity):事务中的所有操作要么全部提交成功,要么全部回滚失败
  • 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不影响其他事务
  • 持久性(Durability):事务一旦提交,其结果永久保存在数据库中

一、事务管理:银行转账示例

1. ACID特性图解

是 否 开始事务 账户A扣款100元 账户B入账100元 转账成功? 提交事务 回滚事务 数据持久化 恢复原始状态

2. 事务控制代码解析

sql 复制代码
-- 银行转账事务示例
BEGIN TRANSACTION; -- 开启事务

-- 账户1扣款
UPDATE accounts 
SET balance = balance - 100 
WHERE id = 1;

-- 账户2入账
UPDATE accounts 
SET balance = balance + 100 
WHERE id = 2;

-- 检查结果
IF (SELECT balance FROM accounts WHERE id = 1) >= 0
    COMMIT; -- 提交事务:所有操作永久生效
    PRINT '转账成功';
ELSE
    ROLLBACK; -- 回滚事务:撤销所有操作
    PRINT '余额不足,转账失败';
END IF;

3. 隔离级别问题示例

脏读问题

sql 复制代码
-- 事务A(未提交)
BEGIN TRANSACTION;
UPDATE products SET stock = stock - 1 WHERE id = 100; -- 库存减1

-- 事务B(读取未提交数据)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT stock FROM products WHERE id = 100; -- 读取到99(未提交的值)

-- 事务A回滚
ROLLBACK;

-- 结果:事务B读取了不存在的数据

幻读(Phantom Read):一个事务在查询范围内插入了新数据,导致另一个事务两次查询结果不同

不可重复读问题

sql 复制代码
-- 事务A
BEGIN TRANSACTION;
SELECT price FROM products WHERE id = 200; -- 返回100

-- 事务B
UPDATE products SET price = 120 WHERE id = 200;
COMMIT;

-- 事务A再次查询
SELECT price FROM products WHERE id = 200; -- 返回120
COMMIT;

二、备份与恢复:电商数据库案例

数据库备份 物理备份 逻辑备份 冷备份 热备份 全量备份 增量备份 差异备份

高可用性与灾难恢复

高可用性架构
复制 复制 自动切换 客户端 负载均衡器 主数据库 从数据库1 从数据库2 监控系统

灾难恢复策略

  • 异地容灾:在地理位置不同的数据中心建立备份系统
  • 定期测试恢复流程:确保备份数据可用
  • 备份验证:定期还原备份数据进行验证
  • 日志传输:实时将事务日志传输到远程备份中心

1. 备份策略示例(SQL Server)

sql 复制代码
-- 周日:完全备份
BACKUP DATABASE EcommerceDB 
TO DISK = 'D:\Backup\Ecom_Full.bak'
WITH INIT, NAME = 'Full Backup';

-- 周一至周六:差异备份
BACKUP DATABASE EcommerceDB 
TO DISK = 'D:\Backup\Ecom_Diff.bak'
WITH DIFFERENTIAL, NAME = 'Differential Backup';

-- 每15分钟:事务日志备份
BACKUP LOG EcommerceDB 
TO DISK = 'D:\Backup\Ecom_Log.trn'
WITH NAME = 'Transaction Log Backup';

2. 恢复流程图示

User DBMS BackupFiles 启动恢复 获取完全备份 Ecom_Full.bak 恢复基础数据库结构 获取最新差异备份 Ecom_Diff.bak 应用最近更改 获取日志备份 Ecom_Log1.trn, Ecom_Log2.trn... 按顺序应用所有日志 数据库恢复完成 User DBMS BackupFiles

3. 时间点恢复示例

sql 复制代码
-- 恢复到7月8日14点的状态
RESTORE DATABASE EcommerceDB 
FROM DISK = 'D:\Backup\Ecom_Full.bak'
WITH NORECOVERY; 

RESTORE LOG EcommerceDB 
FROM DISK = 'D:\Backup\Ecom_Log.trn'
WITH STOPAT = '2025-07-08 14:00:00', RECOVERY;

恢复效果对比

复制代码
数据库状态时间线:
7月8日12:00 ─── 14:00(故障点)─── 15:00

恢复操作:
完全备份(12:00) + 日志备份(12:00-14:00) = 恢复到14:00状态

5. 高可用技术对比

同步复制 异步复制 日志传送
主数据库
备用数据库1 备用数据库2 备用数据库3


场景:在线商城订单处理

备份系统 事务管理 开始事务 是 否 数据变更 日志记录 备份订单数据 每小时差异备份 备份事务日志 每5分钟日志备份 扣减库存 用户下单 生成订单 记录日志 支付成功? 提交事务 回滚事务

三、数据库并发控制

一、为什么需要并发控制?

当多个用户同时访问数据库时,会出现经典问题:
并发操作 数据不一致 丢失更新 脏读 不可重复读 幻读

问题示例:银行账户并发访问
sql 复制代码
-- 事务A(转账)
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 读到500
UPDATE accounts SET balance = 500 - 100 WHERE id = 1;

-- 同时事务B(存款)
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- 也读到500
UPDATE accounts SET balance = 500 + 200 WHERE id = 1;
COMMIT;

-- 事务A提交后:
-- 预期:500 - 100 + 200 = 600
-- 实际:500 + 200 = 700(丢失了-100的操作)

二、核心并发控制技术

并发控制技术分类

并发控制技术 锁机制 时间戳排序 多版本并发控制 MVCC 乐观并发控制 共享锁 S锁 排他锁 X锁 意向锁 行级锁 表级锁

三、锁机制详解

锁的类型

共享锁(Shared Lock, S 锁)

  • 允许其他事务读取同一资源

  • 多个事务可同时持有同一资源的共享锁

  • 语法示例(MySQL):

    sql 复制代码
    SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;

排他锁(Exclusive Lock, X 锁)

  • 禁止其他事务读取或修改同一资源

  • 同一资源上只能有一个排他锁

  • 语法示例(MySQL):

    sql 复制代码
    SELECT * FROM table_name WHERE ... FOR UPDATE;
锁的粒度

表级锁

  • 对整张表加锁
  • 实现简单,开销小,但并发度低
  • 适用于批量操作(如 TRUNCATE、ALTER TABLE)

行级锁

  • 对表中特定行加锁
  • 并发度高,但实现复杂,开销大
  • 适用于高并发事务处理(如 OLTP 系统)

意向锁

  • 表示事务后续可能对表或行加锁
  • 分为意向共享锁(IS)和意向排他锁(IX)
  • 用于快速判断表中是否有行被锁定

锁表示例:

sql 复制代码
-- 事务A(获取排他锁)
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- X锁
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- 事务B(尝试读取)
SELECT balance FROM accounts WHERE id = 1; -- 被阻塞,等待锁释放
三级锁协议

三级锁协议是并发控制的基础框架,定义了事务在不同阶段如何获取和释放锁:
一级锁协议 防止丢失更新 二级锁协议 防止脏读 三级锁协议 防止不可重复读

一级锁协议(基本锁协议)
  • 核心规则:写数据前必须加排他锁(X 锁),事务结束才释放

  • 解决问题:丢失更新

  • 示例

    sql 复制代码
    -- 事务A
    BEGIN;
    SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; -- 获取X锁
    -- 此时事务B的更新请求会被阻塞
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    COMMIT; -- 释放锁
二级锁协议(扩展锁协议)
  • 核心规则

    • 写数据前加X锁(事务结束释放)
    • 读数据前加共享锁(S 锁)(读完立即释放)
  • 解决问题:丢失更新 + 脏读

  • 示例

    sql 复制代码
    -- 事务A
    BEGIN;
    SELECT balance FROM accounts WHERE id = 1 LOCK IN SHARE MODE; -- 获取S锁
    -- 其他事务可以读但不能写
    COMMIT; -- S锁在SELECT后立即释放
    
    -- 事务B
    BEGIN;
    SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 获取X锁(阻塞直到A释放S锁)
三级锁协议(严格锁协议)
  • 核心规则

    • 写数据前加X锁(事务结束释放)
    • 读数据前加S锁(事务结束释放)
  • 解决问题:丢失更新 + 脏读 + 不可重复读

  • 示例

    sql 复制代码
    -- 事务A
    BEGIN;
    SELECT balance FROM accounts WHERE id = 1 LOCK IN SHARE MODE; -- 获取S锁
    -- 此时事务B的更新会被阻塞
    SELECT balance FROM accounts WHERE id = 1; -- 第二次读取(结果相同)
    COMMIT; -- 释放S锁
三级锁协议对比
锁协议 防止丢失更新 防止脏读 防止不可重复读 锁释放时机
一级 X 锁在事务结束释放
二级 S 锁在读取后释放
三级 S 锁和 X 锁在事务结束释放

死锁(Deadlock)

定义

  • 两个或多个事务互相等待对方释放锁资源,导致所有事务都无法继续执行的状态。

死锁示例
持有锁L1 持有锁L2 事务T1 等待锁L2 事务T2 等待锁L1

死锁产生的四个必要条件

  1. 互斥条件:资源不能被多个事务同时访问
  2. 占有并等待:事务持有锁的同时请求其他锁
  3. 不可抢占:锁只能由持有它的事务主动释放
  4. 循环等待:事务之间形成循环等待锁的链

死锁处理策略

  • 预防:破坏死锁产生的四个必要条件之一
  • 检测与恢复:DBMS 定期检测死锁,选择代价最小的事务回滚
  • 超时机制:事务等待锁超过一定时间后自动回滚

MySQL 死锁检测与处理

sql

sql 复制代码
-- 查看死锁日志
SHOW ENGINE INNODB STATUS;

-- 设置死锁超时时间(默认50秒)
SET innodb_lock_wait_timeout = 10;

-- 启用死锁检测(默认开启)
SET innodb_deadlock_detect = ON;

活锁(Livelock)

事务A 事务B 数据库 请求锁L(成功) 请求锁L(失败,等待) 释放锁L(临时回退) 请求锁L(成功) 重试请求锁L(失败,等待) 释放锁L(临时回退) 重试... 重试... loop [无限循环] 事务A 事务B 数据库

定义

  • 事务因不断收到锁请求被拒绝而无法继续执行的状态。

活锁示例

  • 事务 T1 持有锁 L,事务 T2 和 T3 循环请求锁 L
  • DBMS 采用公平锁策略,轮流授予 T2 和 T3 锁,但 T1 始终未释放锁
  • 导致 T2 和 T3 始终无法获取锁而陷入活锁

活锁处理策略

  • 先来先服务(FCFS):按请求锁的顺序授予锁
  • 随机后退:请求锁失败的事务随机等待一段时间后重试
  • 优先级机制:为事务分配优先级,高优先级事务优先获取锁
死锁与活锁对比
类型 产生原因 状态特征 解决方法
死锁 事务间循环等待锁 所有事务停滞,无法继续执行 死锁检测、超时机制、锁排序
活锁 事务频繁被拒绝获取锁 事务持续运行但无法完成 公平锁策略、随机后退、优先级机制

死锁处理机制

死锁处理策略:

是 否 死锁检测 发现死锁? 选择牺牲者 回滚事务 释放锁资源 继续监控

现代并发控制优化

1. 乐观并发控制(OCC)

无冲突 有冲突 事务开始 读取数据 本地修改 提交验证 写入数据库 回滚重试

2. 多粒度锁定

数据库 表1 表2 行1-100 行101-200 行201-300

3. 索引并发控制(B+树示例)

复制代码
         [根节点]
        /       \
[叶节点A]       [叶节点B]
 1│3│5           7│9│11

插入操作:
1. 对根节点加S锁
2. 找到叶节点A,升级为X锁
3. 插入数据4
4. 释放所有锁
相关推荐
霸王龙的小胳膊13 分钟前
泛微虚拟视图-数据虚拟化集成
数据库
灵犀学长33 分钟前
解锁Spring Boot多项目共享Redis:优雅Key命名结构指南
数据库·redis
轩情吖35 分钟前
Qt的信号与槽(二)
数据库·c++·qt·信号·connect·信号槽·
ZeroNews内网穿透41 分钟前
服装零售企业跨区域运营难题破解方案
java·大数据·运维·服务器·数据库·tcp/ip·零售
可观测性用观测云1 小时前
达梦数据库监控观测最佳实践
数据库
时序数据说1 小时前
IoTDB:专为物联网场景设计的高性能时序数据库
大数据·数据库·物联网·开源·时序数据库·iotdb
码农小站2 小时前
ClickHouse 时间范围查询:精准筛选「本月数据」
数据库
paopaokaka_luck3 小时前
基于SpringBoot+Vue的非遗文化传承管理系统(websocket即时通讯、协同过滤算法、支付宝沙盒支付、可分享链接、功能量非常大)
java·数据库·vue.js·spring boot·后端·spring·小程序
小疯仔3 小时前
navicat导出数据库的表结构
数据库
TOSUN同星3 小时前
干货分享 | TSMaster DBC编辑器操作指南:功能详解+实战示例
数据库·oracle·编辑器·汽车·软件工程