先决条件 – DBMS 中的计划类型、事务隔离级别
常见的并发问题主要有四种:脏读、丢失读、不可重复读和幻读。
脏读——
当允许事务读取已被另一个尚未提交的事务修改的行时,发生脏读。它主要是由于一次未提交的多个事务而发生的。
例子 –
表 –记录
ID | Cus_Name | Balance |
---|---|---|
1 | S Adam | 100 |
2 | Zee Young | 150 |
交易 –
从 S Adam 账户转账 10 到 Zee Young 账户:
Input:
BEGIN TRY
BEGIN TRANSACTION
UPDATE Table SET Balance = Balance - 10 WHERE ID=1;
UPDATE Table SET Balance = Balance + 10 WHERE ID='C';
COMMIT TRANSACTION
PRINT 'Committed'
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
PRINT 'Not Committed'
END CATCH
Output:
Not committed
通过执行上述查询,输出将是“未提交”,因为存在错误,没有 ID=C。所以那时如果我们想用该行执行另一个事务,那么就会发生脏读。如果两个 UPDATE 查询都成功,则没有部分承诺,只有这样输出才会“已提交”。
执行前:
表 –记录
ID | Cus_Name | Balance |
---|---|---|
1 | S Adam | 100 |
2 | Zee Young | 150 |
执行后:
Input:
BEGIN TRY
BEGIN TRANSACTION
UPDATE Table SET Balance = Balance - 10 WHERE ID=1;
UPDATE Table SET Balance = Balance + 10 WHERE ID='C';
COMMIT TRANSACTION
PRINT 'Committed'
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
PRINT 'Not Committed'
END CATCH
Output:
(1row affected)
(0row affected)
Not Committed
请注意,如果我们输入有效 ID,第一个事务结果将作为已提交或 1 行生效,但第二个不会受到影响。
解释 –
如果我们有一个订票系统,并且一个客户正在尝试预订机票,当时可用的票数为 10,则在完成付款之前,第二个客户想要预订机票,第二次交易将显示第二个客户可用票的数量是 9。如果第一个客户的借记卡或钱包中没有足够的资金,那么第一个交易将回滚,此时 9 个可用座位由第二个交易读取是脏读。
例子:
可用票:第一个客户
- 第一步——
Input: -- Transaction 1 Select *from Bus_ticket;
输出:
ID Bus_Name Available_Seat 1 KA0017 10 - 第二步——
第一位顾客的预约时间Input: --Transaction 1 BEING Transaction UPDATE Bus_Ticket set Available_Seat=9 WHERE ID=1 --Payment for Transaction 1 Waitfor Delay '00.00.30' Rollback transaction
可用票:适用于第 2 位客户,第 1 位客户需支付票款。
- 第三步——
Input: -- Transaction 1 set transaction isolation level read uncommitted Select *from Bus_ticket where ID=1;
输出:
ID Bus_Name Available_Seat 1 KA0017 9
请注意,在第 1 个客户的付款期间,第 2 个交易读取它 9 个席位可用,如果某些第 1 个交易回滚然后可用席位 9 是脏读取数据。第一笔交易回滚后,可用席位再次变为 10。第 2 步和第 3 步同时发生。
事务1回滚后实际可用座位:
ID | Bus_Name | Available_Seat |
---|---|---|
1 | KA0017 | 10 |