如何使数据库事务成为原子(所有部分都完整或没有完成)?

时间:2013-02-20 13:32:01

标签: database transactions

假设我有一个储蓄账户和一个支票账户。我的储蓄账户余额是150美元。我正在尝试将100美元从我的储蓄帐户转移到支票帐户,也将100美元从我的储蓄帐户转移到我朋友的帐户。

将100美元从我的储蓄帐户转移到我的支票帐户的步骤:

1.1。读(current_saving_balance)

1.2。将saving_balance减少100

1.3。将100添加到我的checking_balance

将100美元从我的储蓄帐户转移到朋友帐户的步骤:

2.1。读(current_saving_balance)

2.2。将saving_balance减少100

2.3。将100添加到我朋友的帐户余额

我想同时执行这些事务。如果他们都在开始时读取了saving_balance,那么两者都可以将saving_balance减少100 $,但是,其中只有一个应该能够成功。如何处理银行系统。

3 个答案:

答案 0 :(得分:0)

不需要可序列化的隔离级别(但是,从数据库系统到数据库系统,确切的loggin语义是非常不同的。)

  • 选择更新作为第一个语句,然后执行剩余的事务。 执行select for update的第一个事务将锁定该行,另一个事务将被阻塞,直到第一个事务提交(悲观锁定)
  • 确保执行更新语句时,它仍然具有与读取时相同的值,否则重新执行

  • 没有必要明确地读取数据,一个简单的更新语句就足够了(但是需要有一个逻辑来检查帐户中是否有足够的资金,这可以通过触发来实现。)

答案 1 :(得分:0)

您有实际交易(1.转账100美元.2。转账100美元给朋友) 而你正在尝试的是在单一的技术交易中(开始; ......;提交)。我认为这是错误的方法。您的代码必须反映实际交易,即 开始; ...... 1.转账100美元。 ;承诺; 开始; ...... 2.将100美元转给朋友)。 ;承诺; 有一些数据库功能,它会在每次交易前检查余额,并决定是否保存。

答案 2 :(得分:0)

以下是如何在tSQL中执行此操作,您的数据库的语法可能会有所不同。

BEGIN TRAN

UPDATE  accounts
SET balance = balance-100
WHERE   account='1'

UPDATE  accounts
SET balance = balance + 100
WHERE   account='2'

COMMIT TRAN

我建议您阅读this article以更多地了解数据库事务。

忽略评论中发生的整个可序列化隔离对话。它并没有真正解决你所描述的问题。