ruby-on-rails - Rails 事务不是原子的?
问题描述
我有一个我编写的会计系统,它遵循标准的复式记账法。
复式记账有一个称为“试算表”的功能,您可以在其中验证整个系统是否正确,因为当您运行它时,它总是等于0.00
我已经编写了测试,并且总是在系统“停止”时运行我的试算表,但是在为大量记录播种期间写入大量数据库负载的情况下,我注意到我的试算表在 10 次尝试中有 1 次是错误的。
当它处于静止状态(没有插入)时,它总是正确的0.00
。
当我插入事务时,它们总是在事务中,如下所示:
2000.times do |i|
ActiveRecord::Base.transaction do
puts "#{i} ==================================================================="
entry = JournalEntry.create!(description: 'Purchase mower on credit', user: user)
entry.line_items.create!(amount: Money.from_amount(1551.75).cents, account: property.accounts.find_by(name: 'Equipment'), side: :debit)
entry.line_items.create!(amount: Money.from_amount(1551.75).cents, account: property.accounts.find_by(name: 'Accounts Payable'), side: :credit)
end
end
它在负载下中断的事实让我觉得我不了解 Rails 事务如何工作的重要内容......
这可能是什么原因造成的?
FWIW 我的试算表函数(GeneralLedger.new(property).trial_balance
)执行以下伪 SQL(不在事务中):
SELECT sum(...) WHERE account = 'asset'
SELECT sum(...) WHERE account = 'liability'
SELECT sum(...) WHERE account = 'equity'
SELECT sum(...) WHERE account = 'income'
SELECT sum(...) WHERE account = 'expense'
然后我根据会计公式将它们加在一起得到 0.00:
def trial_balance
balance_category(:asset) - (balance_category(:liability) + balance_category(:equity) + balance_category(:income) - balance_category(:expense))
end
该balance_category
函数触发每个 SELECT 总共 5 次,每个类别一次。
因为它返回 0 这意味着它在插入中途时以某种方式选择......我不知道这是怎么回事?
我可以理解是否创建日记帐分录/行项目不在事务中并且它正在选择中途插入的行,但它应该只在事务结束后从整个组中选择?
解决方案
如果你想避免重复的陈述,把它折叠成一个,这种形式的东西:
SELECT account, SUM(...) AS amount FROM ...
WHERE account IN ('asset', 'liability', ...)
GROUP BY account
你可以像这样获取这些:
where(account: ACCOUNT_TYPES).group(:account).pluck('account, SUM(...)')
ACCOUNT_TYPES
您需要获取的帐户类型数组在哪里。
您始终可以采用这种pluck
形式并转换为快速查找哈希,.to_h
然后像这样使用它:
balance_category = ...where(...)...pluck(...).to_h
balance_category[:asset]
如果您需要默认值,请考虑:
balance_category = Hash.new(0).merge(...where(...)...pluck(...).to_h)
该默认值可以是整数 ( 0
) 或浮点数 ( 0.0
) 或任何东西。
推荐阅读
- java - 使用spring boot data redis模板得到空指针错误
- reactjs - 我如何在旋转木马上制作动画/移动图像以做出反应。哪种格式最好?
- javascript - 当我尝试搜索时,我的 jekyll/github 网站出现错误
- dc.js - 没有过滤器应用于 DC.js 图表时的条件自定义 X 值暗淡名称
- css - 向材料表中的列添加特定的最小宽度
- kotlin - Kotlin 适配器声明问题:类型不匹配:推断类型是 MyTabAdapter 但 RecyclerView.Adapter<(raw) RecyclerView.ViewHolder!>?预计
- typescript - 使用 Typescript 初始化 Text.defaultProps
- node.js - 如何针对特定平台定位节点应用程序
- java - 使用银行App切换功能出错
- c++ - 结构体与 printf() 一起使用