2

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.

programmingfun11
  • 133
  • 2
  • 10
  • 2
    Is it just me, or is there no documentation for `dm-transactions` at all? I certainly can't find it. –  Mar 09 '12 at 17:19

3 Answers3

5

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

Gareve
  • 3,230
  • 2
  • 19
  • 22
Filipe Miguel Fonseca
  • 6,203
  • 1
  • 29
  • 26
4

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.

Jason Sydes
  • 331
  • 2
  • 4
0

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
Xylakant
  • 112
  • 3
  • 1
    Oddly enough, everything inside my sql_statements.each block is being ignored. `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 ` `rescue` `t.rollback` `end` `end ` `end # execute` – programmingfun11 Sep 16 '11 at 13:49
  • 1
    You'll probably need to commit your transaction inside the block :) – Xylakant Sep 16 '11 at 19:55
  • I added t.commit inside the block, but everything inside @sql_statements.each was still ignored. – programmingfun11 Sep 19 '11 at 13:30
  • 4
    I have just been playing around with this and believe that `DataMapper.repository(:whatever).transaction` returns the current transaction and ignores the block. I'm currently using something more like `t = DataMapper::Transaction.new(DataMapper.repository(:whatever).adapter); t.begin; t.within do stuff; end; t.commit` though I would **not** say that this is a normative best-practices i-know-exactly-what-i'm-doing setup :) –  Mar 09 '12 at 17:17