SQL Server笔记(2):事务管理和并发模型

Posted by Kurt on February 24, 2021

Notes from Expert SQL Server Transactions and Locking by Korotkevitch, Dmitri

2.1 事务

事务:指在数据库中查询和修改数据,并保证数据的一致性和持久性的一个工作单元。

– 事务四大特性:ACID.

原子性(Atomicity)- 保证每个事务作为单个工作单元执行,要么全部执行,要么全部不执行。

一致性(Consistency)- 确保任何事务使得数据库从一个一致的状态到另一个统一的状态,且不违反定义的数据库规则和约束。

隔离性(Isolation)- 确保事务中的变化是独立的,且其它事务不可见,直到事务被提交。

持久性(Durability)- 确保在事务提交之后,事务所做的更改是永久的,即使在系统崩溃之后也能存在。SQL Server通过使用预写式日志(WAL, write-ahead logging)来实现持久性,将元数据的变更操作写入到持久稳定的db之前,先预先写入到一个log中,然后再由另外的操作将log apply到外部的持久db里去。在log记录全部写到log文件里之后,事务才算提交成功。

– 并发访问导致的数据读取问题:

脏读(dirty read)- 一个事务读取到其它未提交的事务的数据

不可重复读(non-repeatable reads)- 同一个事务多次读取同样的数据,得到不同的结果。

幻读(phantom reads)- 同一个事务多次读取,得到新的行。

2.2 悲观并发与乐观并发

数据库中有两种并发模型:

悲观并发 – 假定可获取相同数据的多个用户最终会修改并覆盖其他人的更改。在第一个回话写入或修改数据的时候就会锁定。

乐观并发 – 假定获取相同数据的多个用户同时做出更改的可能性很低。数据不会被锁,可能会造成写入冲突并回滚受影响的事务。

悲观并发可能会引入数据锁定。而乐观并发则需要处理写入冲突。

2.3 事务隔离级别

隔离级别 种类 脏读 不可重复读 幻读 写冲突
读未提交(READ UNCOMMITTED) 悲观 ×
读提交(READ COMMITTED) 悲观 × ×
可重复读(REPEATABLE READ) 悲观 × × ×
序列化(SERIALIZABLE) 悲观 × × × ×
读提交快照(READ COMMITTED SNAPSHOT) 读时乐观,写时悲观 × ×
快照 (SNAPSHOT) 乐观 × × ×

悲观隔离级别时,SQL Server通过锁来阻止获取被其它会话修改或读取过的行。

乐观隔离级别时,SQL Server不会锁,而使用行版本(row versioning)来解决。它将修改的行的老版本复制到一个临时的tempdb上(称为version store),其它会话只能从这里读取老的版本。

需要注意的是,即使在乐观隔离级别下,SQL Server仍然会获取锁来防止其它会话同时更新相同的行。

READ COMMITTED SNAPSHOT级别结合了悲观和乐观并发的模型。严格来说,它并不算真正的隔离级别,而是选项来改变读操作时的默认方式。

2.4 使用事务

(1)事务的种类

SQL Server中有三种事务:显式,自动提交和隐式。

显式事务指显式地由代码控制。通过BEGIN TRAN和COMMIT等语句来实现。

自动提交事务 – 事务中的每个执行的语句都会被提交。这样子的事务不能工作在模块级别,如果中间失败,SQL Server不能回滚到事务开始之前,可能会导致逻辑不一致。

隐式事务通过SET IMPLICIT_TRANSACTION ON来使用,当没有活跃的显式事务存在时,SQL Server会自动打开一个新事务,直到COMMIT或ROLLBACK语句。

(2)错误的处理

在修改数据时尽量使用显式事务,从而保证数据一致性。

在事务开始前,设置XACT_ABORT为on,保证数据原子性。

多使用TRY…CATCH语句,并显式回滚事务。

(3)嵌套事务(nested transactions)与保存点(savepoints)

技术上而言SQL Server支持嵌套事务。ROLLBACK语句会回滚整个事务,无论当前嵌套在哪一层。

可以通过SAVE TRANSACTION语句来创造一个保存点,保存事务的状态,从而部分回滚事务到最近的保存点。

第二章结束,这周上班没效率,没时间看书,唉。