张瑞峰的博客

导航

数据库事务简析

软件开发中的挑战

• 多个应用同步运行,多个应用访问同一个数据库

• 简单的解法:每次只有一个应用访问数据库。
问题:造成数据库访问速度问题。

• 更好的方法:多个操作应该原子地在数据库执行

什么情况会出错(脏读)

经理(正在不同项目中平衡预算) CEO(查询整个项目的预算)
-从项目A中减10K
-其中7K增加到项目B -查询总预算:SELECT SUM(money) FROM budget;
-其中3K增加到项目C

这叫做脏读。也就是读写冲突。

什么情况会出错2(不可重复读)

• App1:
SELECT inventory FROM products WHERE pid = 1

• App2:
UPDATE products SET inventory = 0 WHERE pid = 1

• App1:
SELECT inventory * price FROM products WHERE pid = 1

这叫做不可重复读,也就是读写冲突。

什么情况会出错3(丢失更新)

// 正确
• App1:
– Set Account1 = $200
– SetAccount2 = $0
• App2:
– Set Account2 = $200
– SetAccount1 = $0
• At the end: – Total = $200

// 错误
• App 1: Set Account 1 = $200
• App 2: Set Account 2 = $200
• App 1: Set Account 2 = $0
• App 2: Set Account 1 = $0
• At the end: – Total = $0

这叫做丢失更新,也就是读写冲突。

事务

事务就是一系列的语句原子地运行。

BEGIN TRANSACTION
[SQL statements] COMMIT or
ROLLBACK (=ABORT)

ACID 事务

• 原子性(Atomic)

要么状态被事务全部改变,要么所有状态都不改变

// crash!
UPDATE accounts SET bal = bal – 100 WHERE acct = A;
UPDATE accounts SET bal = bal + 100 WHERE acct = B;

// 使用事务
BEGIN TRANSACTION;
UPDATE accounts SET bal = bal – 100 WHERE acct = A;
UPDATE accounts SET bal = bal + 100 WHERE acct = B;
COMMIT;

• 持续性(Consistent)

• 隔离的(Isolated)

事务的作用一个接一个发生。事务之间的运行的环境是隔离的。

// Alice:
BEGIN TRANSACTION;
x = select bal from accounts where acct = A;
x = x+100
update accounts set bal = x where acct = A;
COMMIT;

// Bob:
BEGIN TRANSACTION;
y = select bal from accounts where acct = A;
if y < 100 return “Error” y = y - 100
update accounts set bal = y where acct = A;
COMMIT;

• 持久性(Durable)

一旦事务commit之后,它的结果应该永久存储在数据库中。

事务回滚

如果app无法成功执行完所有的事务操作,那么回滚。回滚后,DB会回到事务操作之前的状态。

不同事务策略

• 每个元素有一个锁

• 每个事务在读写元素之前必须先获取锁

• 如果锁被其他事务拿着那么就等着

• 事务必须在完成后释放锁

• 锁住整个数据库 – SQLite
• 锁住单独一个记录 – SQL Server, DB2, etc.

多版本并发控制(MVCC)

以上内容译自uw cse414

posted on 2021-02-20 17:33  张瑞峰的博客  阅读(56)  评论(0编辑  收藏  举报