想象一下一个使用SQL作为数据库的银行系统。用户A想将一些钱存入用户B的账户。如果他们发送了钱,我们从他们的账户余额中扣除了这笔钱,并且我们想要将这笔钱存入用户B的账户,但突然间我们的数据库崩溃了。
这是否意味着我们从用户A的余额中扣除的钱消失了?嗯,并不是在SQL数据库中,因为它们使用SQL事务来处理这些情况。
事务是一系列作为单一原子单元执行的一个或多个SQL操作。其目的是确保数据库中的数据一致性。事务具有以下属性,通常被称为ACID属性的首字母缩写:
我们使用 BEGIN TRANSACTION 关键字标记SQL事务的开始。
为了保存事务中进行的所有更改,我们将更改 COMMIT 到数据库。
如果在事务中发生了错误,我们可以使用 ROLLBACK 命令回滚事务中进行的所有更改,将数据库恢复到事务开始时的状态。
示例:
让我们回到我们简单的银行应用程序示例,其中您需要从账户A转账100美元到账户B。这涉及两个步骤:
为了使事务成功,必须完成这两个步骤。下面是如何将其写为SQL事务的示例:
BEGIN TRANSACTION;
-- 扣除账户A的余额100美元
UPDATE Accounts
SET balance = balance - 100
WHERE account_id = 'A';
-- 检查账户A是否有足够的余额,如果没有就回滚
IF @@ROWCOUNT = 0
ROLLBACK;
-- 将100美元添加到账户B的余额
UPDATE Accounts
SET balance = balance + 100
WHERE account_id = 'B';
-- 如果一切正常,则提交事务
COMMIT;
此事务执行以下操作:
这确保了要么两个账户都适当地更新,要么在任何一点出现问题时都不应用任何更改,从而保持数据的完整性。
数据库事务的隔离级别确定事务的完整性如何维护以及在多大程度上每个事务与其他事务隔离。
SQL标准定义了四个隔离级别,它们在一致性和性能之间进行权衡。
(1) 读未提交(Read Uncommitted)
(2) 读提交(Read Committed)
(3) 可重复读(Repeatable Read)
(4) 可序列化(Serializable)
使用不同的隔离级别,可能会发生几种现象,比如脏读、不可重复读或幻读。让我们看看这些术语的含义.
脏读发生在一个事务读取由并发未提交事务写入的数据时。因此,如果其他事务回滚,第一个事务将读取从未正式提交到数据库中的数据。
示例:
当事务在其过程中两次检索同一行时,并且两次读取之间行内的值发生更改时,就会发生不可重复读。实质上,另一个事务在两次读取之间修改了该行。
示例:
幻读发生在一个事务期间,另一个事务通过添加(或删除)行到正在读取的记录中来更改数据。这意味着事务中的后续读取可能返回包含新添加行的一组行,或者不包括原始读取的已删除行。
示例:
显然,更高的隔离级别减少了可能发生的现象类型,但以减少并发性和潜在的性能影响为代价。
上一篇:C 关键字详解:程序之魂