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语句来创造一个保存点,保存事务的状态,从而部分回滚事务到最近的保存点。
第二章结束,这周上班没效率,没时间看书,唉。