저는 Rails를 처음 사용하고 있으며 트랜잭션을 처리해야하는 시스템이 있습니다. 사용자는 하나 이상의 사용자가 연결된 거래를 입력 할 수 있습니다. 이 사용자는 거래를하는 사람에게 약간의 돈을 빚지고 있습니다. 예를 들어, Bill은 4 명의 친구에 대해 점심을 구입할 수 있으며이 법안은 125 달러입니다. 그들은 법안을 5 가지 방법으로 나누어 각각 25 달러를 지불해야합니다. 빌은 합계 $ 125를 입력하고 각 친구 (자신을 포함하여)에게 거래 금액으로 25 달러를 지불하게됩니다. 내 컨트롤러와 내 모델에이 목표를 달성하기위한 코드가 있지만 실제로 트랜잭션을 사용하고 올바르게 잠그고 있는지 알 수 없습니다. 또한 컨트롤러에서이 정보를 얻는 것이 관건입니까? 이러한 모든 작업이 함께 발생해야하거나 실패 (원 자성)해야하기 때문에 트랜잭션을 사용하고 있으며 여러 사용자가 동시에 (격리) 제출하려고 할 때 잠금이 필요합니다. 어쩌면 나는 백엔드 DB를 잠금 처리해야합니까? 그것은 이미 그렇게합니까 - 말하자면, MySQL은? 감사.Rails 3 - 트랜잭션 및 잠금
trans_controller.rb
class TransController < ApplicationController
# POST trans/
def create
@title = "Create Transaction"
trans_successful = false
# Add the transaction from the client
@tran = Tran.new(params[:tran])
# Update the current user
@tran.submitting_user_id = current_user.id
# Update the data to the database
# This call commits the transaction and transaction users
# It also calls a method to update the balances of each user since that isn't
# part of the regular commit (why isn't it?)
begin
@tran.transaction do
@tran.save!
@tran.update_user_balances
trans_successful = true
end
rescue
end
# Save the transaction
if trans_successful
flash[:success] = 'Transaction was successfully created.'
redirect_to trans_path
else
flash.now[:error] = @tran.errors.full_messages.to_sentence
render 'new'
end
end
tran.rb
class Tran < ActiveRecord::Base
has_many :transaction_users, :dependent => :destroy, :class_name => 'TransactionUser'
belongs_to :submitting_user, :class_name => 'User'
belongs_to :buying_user, :class_name => 'User'
accepts_nested_attributes_for :transaction_users, :allow_destroy => true
validates :description, :presence => true,
:length => {:maximum => 100 }
#validates :total, :presence => true
validates_numericality_of :total, :greater_than => 0
validates :submitting_user_id, :presence => true
validates :buying_user_id, :presence => true
#validates_associated :transaction_users
validate :has_transaction_users?
validate :has_correct_transaction_user_sum?
validate :has_no_repeat_users?
def update_user_balances
# Update the buying user in the transaction
self.buying_user.lock!
# Update the user's total, since they were in the transction
self.buying_user.update_attribute :current_balance, self.buying_user.current_balance - self.total
# Add an offsetting transaction_user for this record
buying_tran_user = TransactionUser.create!(:amount => -1 * self.total, :user_id => self.buying_user_id, :tran => self)
#if buying_tran_user.valid?
# raise "Error"
#end
# Loop through each transaction user and update their balances. Make sure to lock each record before doing the update.
self.transaction_users.each do |tu|
tu.user.lock!
tu.user.update_attribute :current_balance, tu.user.current_balance + tu.amount
end
end
def has_transaction_users?
errors.add :base, "A transcation must have transaction users." if self.transaction_users.blank?
end
def has_correct_transaction_user_sum?
sum_of_items = 0;
self.transaction_users.inspect
self.transaction_users.each do |key|
sum_of_items += key.amount if !key.amount.nil?
end
if sum_of_items != self.total
errors.add :base, "The transcation items do not sum to the total of the transaction."
end
end
def has_no_repeat_users?
user_array = []
self.transaction_users.each do |key|
if(user_array.include? key.user.email)
errors.add :base, "The participant #{key.user.full_name} has been listed more than once."
end
user_array << key.user.email
end
end
end