Rails 嵌套事务
Rails nested transactions
我正在尝试制作 rails 应用程序,但我遇到了这个问题。
我有嵌套事务,虽然它们一直在工作。但是,我发现它们不能正常工作。
这是用户服务
class UserService
def self.reduce_balance!(user, delta, attachmentable)
ActiveRecord::Base.transaction do
user.balance.amount -= delta
balance_decrease = BalanceDecrease.new(user: user, attachmentable: attachmentable, balance_before: user.balance.amount_was, amount: delta)
user.balance.save!
balance_decrease.save!
end
return true
end
end
有游戏服务
class GameService
def self.take_spot(user, spot)
if UserService.have_enough_money? user, game.spot_price
begin
ActiveRecord::Base.transaction do
spot.free = false
spot.user = user
spot.save!
UserService.reduce_balance!(user, game.spot_price, spot)
return res = {success: true, json: spot, status: 200}
end
rescue => e
return res = {json: {error: 1, error_message: "Something gone wrong"}, status: 500}
end
else
return res = {json: {error: 1, error_message: "You don't have enough money"}, status: 400}
end
end
end
我的控制器是
def update
@res = GameService.take_spot current_user, @spot
return render json: @res[:json], status: @res[:status] unless @res[:success]
end
1700 条查询中有 1 条以某种方式出错:现货已被购买,余额未减少。 This is picture of json
json文件(下图):
{
"id": 1759,
"type": "BalanceDecrease",
"balance_before": "950.00",
"amount": "10.00",
"spot": {
"id": 1965,
"number": 7,
"free": false,
"game": {
"id": 19,
"name": "M249 | Блокировка",
"img_url": "(img url)",
"stattrak": false,
"spot_price": "10.00",
"state": "ended",
"created_at": "2015-11-26T23:20:28.081+03:00",
"updated_at": "2015-11-26T23:20:59.406+03:00"
},
"created_at": "2015-11-26T23:20:28.087+03:00",
"updated_at": "2015-11-26T23:20:57.270+03:00"
}
},
{
"id": 1758,
"type": "BalanceDecrease",
"balance_before": "950.00",
"amount": "10.00",
"spot": {
"id": 1964,
"number": 6,
"free": false,
"game": {
"id": 19,
"name": "M249 | Блокировка",
"img_url": "(img url)",
"stattrak": false,
"spot_price": "10.00",
"state": "ended",
"created_at": "2015-11-26T23:20:28.081+03:00",
"updated_at": "2015-11-26T23:20:59.406+03:00"
},
"created_at": "2015-11-26T23:20:28.087+03:00",
"updated_at": "2015-11-26T23:20:57.282+03:00"
}
}
我有 10 美元的 DigitalOcean 水滴。会不会是问题所在?
ActiveRecord::Rollback
不会传播到包含事务块之外,因此父事务不会收到嵌套在子事务中的异常。
为确保父事务收到回滚,您必须向子事务添加 requires_new: true
选项。
查看 this article and docs 了解更多详情。
所以将它应用到你的案例中,你应该user_service.rb
如下:
class UserService
def self.reduce_balance!(user, delta, attachmentable)
ActiveRecord::Base.transaction(requires_new: true) do
# code omitted
end
end
end
您的问题源于您使用交易的方式。
无论何时嵌套它们,都必须使用 requires_new: true
ActiveRecord::Base.transaction do
ActiveRecord::Base.transaction(requires_new: true) do
end
end
解释得很好in the doc。
顺便说一句,总是使用 requires_new: true
.
也没什么坏处
旁注,您似乎使用服务对象并将它们链接起来,也许 this would interest you。
我正在尝试制作 rails 应用程序,但我遇到了这个问题。 我有嵌套事务,虽然它们一直在工作。但是,我发现它们不能正常工作。
这是用户服务
class UserService
def self.reduce_balance!(user, delta, attachmentable)
ActiveRecord::Base.transaction do
user.balance.amount -= delta
balance_decrease = BalanceDecrease.new(user: user, attachmentable: attachmentable, balance_before: user.balance.amount_was, amount: delta)
user.balance.save!
balance_decrease.save!
end
return true
end
end
有游戏服务
class GameService
def self.take_spot(user, spot)
if UserService.have_enough_money? user, game.spot_price
begin
ActiveRecord::Base.transaction do
spot.free = false
spot.user = user
spot.save!
UserService.reduce_balance!(user, game.spot_price, spot)
return res = {success: true, json: spot, status: 200}
end
rescue => e
return res = {json: {error: 1, error_message: "Something gone wrong"}, status: 500}
end
else
return res = {json: {error: 1, error_message: "You don't have enough money"}, status: 400}
end
end
end
我的控制器是
def update
@res = GameService.take_spot current_user, @spot
return render json: @res[:json], status: @res[:status] unless @res[:success]
end
1700 条查询中有 1 条以某种方式出错:现货已被购买,余额未减少。 This is picture of json
json文件(下图):
{
"id": 1759,
"type": "BalanceDecrease",
"balance_before": "950.00",
"amount": "10.00",
"spot": {
"id": 1965,
"number": 7,
"free": false,
"game": {
"id": 19,
"name": "M249 | Блокировка",
"img_url": "(img url)",
"stattrak": false,
"spot_price": "10.00",
"state": "ended",
"created_at": "2015-11-26T23:20:28.081+03:00",
"updated_at": "2015-11-26T23:20:59.406+03:00"
},
"created_at": "2015-11-26T23:20:28.087+03:00",
"updated_at": "2015-11-26T23:20:57.270+03:00"
}
},
{
"id": 1758,
"type": "BalanceDecrease",
"balance_before": "950.00",
"amount": "10.00",
"spot": {
"id": 1964,
"number": 6,
"free": false,
"game": {
"id": 19,
"name": "M249 | Блокировка",
"img_url": "(img url)",
"stattrak": false,
"spot_price": "10.00",
"state": "ended",
"created_at": "2015-11-26T23:20:28.081+03:00",
"updated_at": "2015-11-26T23:20:59.406+03:00"
},
"created_at": "2015-11-26T23:20:28.087+03:00",
"updated_at": "2015-11-26T23:20:57.282+03:00"
}
}
我有 10 美元的 DigitalOcean 水滴。会不会是问题所在?
ActiveRecord::Rollback
不会传播到包含事务块之外,因此父事务不会收到嵌套在子事务中的异常。
为确保父事务收到回滚,您必须向子事务添加 requires_new: true
选项。
查看 this article and docs 了解更多详情。
所以将它应用到你的案例中,你应该user_service.rb
如下:
class UserService
def self.reduce_balance!(user, delta, attachmentable)
ActiveRecord::Base.transaction(requires_new: true) do
# code omitted
end
end
end
您的问题源于您使用交易的方式。
无论何时嵌套它们,都必须使用 requires_new: true
ActiveRecord::Base.transaction do
ActiveRecord::Base.transaction(requires_new: true) do
end
end
解释得很好in the doc。
顺便说一句,总是使用 requires_new: true
.
旁注,您似乎使用服务对象并将它们链接起来,也许 this would interest you。