Rails交易不是原子的吗?

时间:2019-05-05 22:14:16

标签: ruby-on-rails ruby postgresql activerecord ruby-on-rails-5

我有一个写的会计系统,该系统遵循标准的双项会计惯例。

双重记账功能有一个称为“试用余额”的功能,您可以在其中验证整个系统的正确性,因为在运行该系统时,它始终等于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事务的工作方式不是很重要……

可能是什么原因造成的?

首先,我的试用余额功能(GeneralLedger.new(property).trial_balance)执行以下pseodo-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,这意味着它以某种方式选择何时插入其中途...........我不知道这是怎么回事?

我可以理解,日记帐分录/行项目的创建是否不在事务中,而它是在选择插入行的中途进行选择,但是它应该仅在事务结束后从整个组中进行选择?

1 个答案:

答案 0 :(得分:1)

如果要避免重复的语句,请将其折叠为以下形式:

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)或任何其他值。