Question

I have a class that executes SQL statements (updates, inserts, and deletes) that are stored in a YAML file. I would like all the statements to be part of one transaction. If any of the SQL statements fail, then they would be rolled back. If all of the statements are successful, then they would be committed. I'm connecting to a MySQL database. Here is my code:

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

I'd like to have all of my @adapter.execute calls be part of one transaction. I've looked at the code in the dm-transactions gem, but I can't figure out how to use it in this context.

Was it helpful?

Solution

Use this to embody your SQL statements in a transaction and rollback if an error occurs:

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

Take a look at Using transactions with Ruby DataMapper and dm-transactions_spec.rb

OTHER TIPS

As far as I can tell, you no longer need to call rollback() for a transaction to be rolled back. You merely need to enclose it in a transaction block, like so:

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

At least, that's how I read the 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

I've been writing a sizable application using DataMapper with plenty of transactions and without the use of rollback(), and all of my failed transactions always rollback.

Also, from what I remember about ActiveRecord (it's been a year since I've used AR), the DataMapper transaction behavior mimics the AR behavior.

Im principle, the response is still correct. User.transaction will open a transaction on the repository (database) that the model "User" is attached to. A more generic way is

DataMapper.repository(:default).transaction do |t|
    t.commit
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top