【问题标题】:How can transactions be utilized in Ruby DataMapper?如何在 Ruby DataMapper 中使用事务?
【发布时间】:2011-09-16 12:56:38
【问题描述】:

我有一个执行存储在 YAML 文件中的 SQL 语句(更新、插入和删除)的类。我希望所有陈述都成为一项交易的一部分。如果任何 SQL 语句失败,那么它们将被回滚。如果所有语句都成功,那么它们将被提交。我正在连接到 MySQL 数据库。这是我的代码:

require 'dm-core'

class SqlExecuter

  def initialize(input_yaml_file_name)
    @input_yaml_file_name = input_yaml_file_name
    @adapter = DataMapper.repository(:default).adapter
    @sql_statements = YAML::load(File.open(input_yaml_file_name))
  end

  def execute()
    puts "Executing SQL statements in #{@input_yaml_file_name} file...."

    @sql_statements.each do | sql_statement |
      @adapter.execute(sql_statement)
    end
  end
end # class SqlExecuter

我想让我的所有@adapter.execute 调用成为一个事务的一部分。我查看了 dm-transactions gem 中的代码,但不知道如何在这种情况下使用它。

【问题讨论】:

  • 只有我一个人,还是根本没有dm-transactions 的文档?我肯定找不到。

标签: ruby ruby-datamapper


【解决方案1】:

使用它在事务中体现您的 SQL 语句并在发生错误时回滚:

require 'dm-transactions'
YourModel.transaction do |t|
  begin
    @sql_statements.each do |sql_statement|
      DataMapper.repository(:default).adapter.execute(sql_statement)
    end
  rescue DataObjects::Error
    t.rollback
  end
end

看看Using transactions with Ruby DataMapperdm-transactions_spec.rb

【讨论】:

  • 只要我的任意 SQL 语句涉及与 YourModel 有关系的表,上面的方法对我有用。谢谢。
【解决方案2】:

据我所知,您不再需要调用 rollback() 来回滚事务。您只需要将其包含在事务块中,如下所示:

YourModel.transaction do
  @sql_statements.each do |sql_statement|
    DataMapper.repository(:default).adapter.execute(sql_statement)
  end
end

至少,这就是我阅读dm-transactions spec about rollbacks的方式:

it 'should rollback when an error is raised in a transaction' do
  @user_model.all.size.should == 0
  lambda {
    @user_model.transaction do
      @user_model.create(:name => 'carllerche')
      raise 'I love coffee'
    end
  }.should raise_error('I love coffee')
  @user_model.all.size.should == 0
end

我一直在使用 DataMapper 编写一个相当大的应用程序,其中包含大量事务并且没有使用 rollback(),并且我所有失败的事务总是回滚。

此外,根据我对 ActiveRecord 的记忆(我使用 AR 已经一年了),DataMapper 事务行为模仿了 AR 行为。

【讨论】:

    【解决方案3】:

    我原则上,响应仍然是正确的。 User.transaction 将在模型“用户”附加到的存储库(数据库)上打开一个事务。更通用的方式是

    DataMapper.repository(:default).transaction do |t|
        t.commit
    end
    

    【讨论】:

    • 奇怪的是,我的 sql_statements.each 块中的所有内容都被忽略了。 def execute()puts "Executing SQL statements in #{@input_yaml_file_name} file....\n"DataMapper.repository(:default).transaction do |t|begin@sql_statements.each do | sql_statement | result = @adapter.execute(sql_statement)end rescuerescuet.rollbackt.rollbackend@987653332@pan@9876
    • 你可能需要在块内提交你的事务:)
    • 我在块中添加了 t.commit,但 @sql_statements.each 中的所有内容仍然被忽略。
    • 我一直在玩这个,并相信DataMapper.repository(:whatever).transaction 返回当前事务并忽略该块。我目前正在使用更像t = DataMapper::Transaction.new(DataMapper.repository(:whatever).adapter); t.begin; t.within do stuff; end; t.commit 的东西,尽管我说这是一个规范的最佳实践我知道我在做什么设置:)
    猜你喜欢
    • 2013-08-28
    • 1970-01-01
    • 2023-04-07
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多