事务就是对数据库的一系列操作,这些操作要么同时成功,要么同时失败。
事务四大特征(ACID)
原子 一致 隔离 持久
举个例子:
假设你要从银行帐户A中转移100美元到帐户B。如果你不使用事务,以下情况可能发生:
-
扣除帐户A的100美元。
-
在将100美元添加到帐户B之前,系统崩溃或出现错误。
这将导致帐户A损失100美元,而帐户B没有收到任何款项。这是一个不一致的状态。
使用事务,你可以这样做:
-
开始一个事务。
-
扣除帐户A的100美元。
-
将100美元添加到帐户B。
-
提交事务。
如果任何一步出现问题,你可以回滚(撤销)整个事务,确保不会发生不一致的情况。事务保证了这些操作要么全部成功,要么全部失败,从而保持了数据的一致性。
简而言之,事务用于确保多个数据库操作的原子性,要么全部执行,要么一个都不执行,从而避免了数据错误或不一致。
如何去执行事务
-
开启事务: 你需要使用
START TRANSACTION
、BEGIN
或SET autocommit=0
来显式地开启一个事务。这将告诉MySQL,你要开始一个事务,后续的SQL语句将被视为事务的一部分。例如:sqlCopy codeSTART TRANSACTION; -- 或者 BEGIN; -- 或者 SET autocommit=0;
-
执行SQL操作: 在事务内执行需要的SQL操作,如插入、更新、删除数据等。这些操作将在同一个事务中执行,要么全部成功,要么全部失败。例如:
sqlCopy codeUPDATE accounts SET balance = balance - 100 WHERE account_id = 1; INSERT INTO transaction_history (account_id, amount, transaction_type) VALUES (1, 100, 'debit');
-
提交事务: 如果所有操作都执行成功,你可以使用
COMMIT
来提交事务,将所有更改永久保存到数据库中。这时事务被确认。例如:sqlCopy code COMMIT;
-
回滚事务: 如果在事务执行过程中出现错误或者你想取消事务,可以使用
ROLLBACK
来回滚事务,撤销所有已执行的操作。例如:sqlCopy code ROLLBACK;
-
设置保存点(Savepoint): 你还可以使用
SAVEPOINT
来设置一个保存点,以便在事务执行过程中部分回滚。这允许你在不影响整个事务的情况下撤销一部分操作。例如:sqlCopy codeSAVEPOINT my_savepoint; -- 执行一些操作 ROLLBACK TO my_savepoint; -- 回滚到指定保存点
-
禁用/启用自动提交: 默认情况下,MySQL处于自动提交模式,每个SQL语句都自动成为一个独立的事务。你可以使用
SET autocommit=0;
来禁用自动提交,使多个SQL操作成为一个事务,然后手动提交或回滚。例如:sqlCopy codeSET autocommit=0; -- 在此执行多个SQL操作 COMMIT; -- 手动提交事务
让我们通过一个现实生活中的例子来说明隔离级别的概念:
例子:银行账户转账
假设你有一个银行账户,希望将一些资金从你的账户转移到朋友的账户。这个操作涉及到两个银行账户:你的账户和朋友的账户。在数据库中,每个账户都有一个余额字段。
现在,我们来看看不同隔离级别下可能发生的情况:
-
脏读(Dirty Read):
你开始转账,减少你的账户余额,但在操作未完成时,系统崩溃或出现错误。此时,你的账户余额已经减少,但资金尚未到达朋友的账户。这导致了不一致的状态,因为资金实际上并没有成功转移到朋友的账户。
-
幻读(Phantom Read):
你开始查询你的账户余额,然后在查询之后,系统更新了另一笔交易,将资金从你的账户转移到朋友的账户。然后,你再次查询你的余额,但这次你看到的余额已经减少了,因为你看到了新的更新。这导致了幻读,因为查询结果在两次查询之间发生了变化。
-
可重复读(Repeatable Read):
你开始查询你的账户余额,并在查询后更新了另一笔交易,将资金转移到朋友的账户。然后,你再次查询你的余额,但这次你看到的余额仍然是之前的余额,没有变化。这是因为在可重复读隔离级别下,查询结果在整个事务期间保持不变。
-
序列化(Serializable):
你开始查询你的账户余额,然后在查询之后更新了另一笔交易,将资金转移到朋友的账户。然后,你尝试再次查询你的余额,但此时你的查询被阻塞,直到另一笔交易完成。只有在另一笔交易完成后,你才能继续查询,这确保了最高级别的一致性,但可能会导致一些等待时间。
这个例子说明了不同隔离级别下可能发生的情况,以及每个隔离级别如何影响事务的行为和数据一致性。在实际应用中,选择合适的隔离级别取决于应用程序的需求和性能要求。