rails实现“事务”的方法

在学习数据库时,曾经提到事务,最典型的一个实例就是银行转账的问题。
A帐户向B帐户转账100块,这个事情一定要发生两件事情,A的帐户上减去100块,B的账户上加上100块。如果半路发生问题而中断这个事情,那么必须回滚到初始状态。
下面来看一下用rails来实现这个例子:

首先,建立模型类account, 数据迁移:

在account类中定义方法:

实施数据迁移。运行console

>> peter = Account.create(:balance=>100, :number=>"12345")
>> paul = Account.create(:balance=>200, :number=>"54321")
#create直接创建并保存到accounts表中
现在数据库中的内容#SELECT * FROM account_development.account


继续在console里运行:
>> Account.transaction do
?> paul.deposit(10)
>> peter.withdraw(10)
>> end
此时数据库中的内容:


现在再来看看异常情况,1.从peter帐户上转350出去给peter
>> Account.transaction do
?> paul.deposit(350)
>> peter.withdraw(350)
>> end
------
这时抛出了异常:
ActiveRecord::RecordInvalid: Validation failed: Balance is negative!
---数据库还是保持原样:

2.从peter账户上转10出去给tom

>> Account.transaction do
?> paul.deposit(10)
>> tom.withdraw(10)
>> end

----抛出异常:
NameError: undefined local variable or method `tom' for #<Object:0x389a0>
数据库依然保持原样。

虽然数据库依然保持原样,但是模型对象会发生变化,look:

现在还是恢复原状,peter有100块,paul有200块


现在执行:

结果出乎意料, 
Transfer aborted!
Paul has  550.0
peter has -250.0

模型对象已经被改变了!
原因就在于ActiveRecord并没有跟踪对象在事务前后的状态,实际上它也跟踪不了, 因为没有一种简单的办法可以知道哪些模型对象参与了事务。为了解决这个问题,我们可以把涉及一次事务的模型对象以参数的形式明确的告诉transaction




这次结果就跟我们料想的一样了:

Transfer aborted!
Paul has  200.0
peter has 100.0

现在可以将转账的方法写到Account类中去了,一次转账涉及两个帐户, 并且不是由其中的任何一个来发起的, 所以这个方法时一个类方法, 接受两个account对象作为参数:



试试在console下使用这个方法:
>> peter=Account.find(1)
>> paul=Account.find(2)
>> Account.transfer(peter, paul, 350) rescue puts "Transfer aborted!"
#结果:
#Transfer aborted!
=> nil
------
>> puts "Paul has #{paul.balance}"
#结果
Paul has 200.0
=> nil
------
>> puts "Peter has #{peter.balance}"
#结果:
Peter has 100.0
=> nil
-------
让事务自动恢复对象状态也有一个缺点:你将无法获知验证过程中出现的错误信息,非法的对象不会被保存,事务会将所有修改回滚,但没有什么简单方法可以知道究竟哪里出了错。




本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/96738,如需转载请自行联系原作者
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值