Wrap Migration in Transaction

Correct me if I’m wrong, but it appears to me that rake migrate does not
wrap its execution in a transaction. Is this right? If so, why not?
And, is it possible at all to wrap a rake migrate in a DB transaction?

I’ve tried:
def self.up
ActiveRecord::Base.transaction do
…migration stuff…
raise “My Error”
end
end

“My Error” is thrown but the transaction is not rolled back. Is raising
an exception the proper way to invoke an ActiveRecord transaction
rollback?

I’ve also tried doing:
ActiveRecord::Base.transation do
%x[rake migrate]
end

But this, obviously, doesn’t work since %x[rake migrate] spanws a new
process outside of the scope of the transactioning.

Any ideas?

Hello Caleb,

I’ve also tried doing:
ActiveRecord::Base.transation do
%x[rake migrate]
end

But this, obviously, doesn’t work since %x[rake migrate]
spanws a new process outside of the scope of the
transactioning.

Any ideas?

To invoke a Rake task in a migration, you can do :

def self.up
Rake::Task[my_task].invoke
end

I have tried with : Rake::Task[‘stats’].invoke and it works.
However, it can be dangerous, what will happen with a
Rake::Task[‘db:migrate’] ? infinite loop ? :slight_smile: it could be a mess…
I think a rake db task would work, but you have to be careful.

HTH,
РJean-Fran̤ois.


Ã? la renverse.

Caleb wrote:

Correct me if I’m wrong, but it appears to me that rake migrate does not
wrap its execution in a transaction. Is this right? If so, why not?
And, is it possible at all to wrap a rake migrate in a DB transaction?

I don’t know if this is true of all databases, but for mysql this won’t
be possible most of the time (although it would be really useful). The
problem with mysql is that there are a bunch of statements that cause an
implicit commit and this list includes most of the things you do in a
migration: adding/removing indexes, ALTER TABLE, creating tables. So
even if you do wrap your migration in a transaction, just about anything
you do in your migration will commit the transaction.

Fred

Jean-François wrote:

To invoke a Rake task in a migration, you can do :

def self.up
Rake::Task[my_task].invoke
end

When I do the following from the Rails console:
Rake::Task[‘stats’].invoke

I get the following error:
RuntimeError: Don’t know how to build task ‘stats’
from
/usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:1449:in []' from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.1/lib/rake.rb:455:in[]’
from (irb):

While something like Rake::Task[my_task].invoke is exactly what I’m
trying to do, I think you got things a bit backwards. I need to invoke
Rake migrate from another class, not invoke a Rake task from within a
migration. Any idea as to why I’m getting the console error above? I’d
assume (maybe a poor assumption?) that once I can get it to work in the
Rails console then it should work from any line of code in my Rails app.

Fred wrote:

The problem with mysql is that there are a bunch of statements that cause an
implicit commit and this list includes most of the things you do in a
migration: adding/removing indexes, ALTER TABLE, creating tables. So
even if you do wrap your migration in a transaction, just about anything
you do in your migration will commit the transaction.

Good point! Fortunately, I’m using these migrations to do data changes
(INSERT/UPDATE/DELETE), NOT SCHEMA changes (ALTER/DROP/CREATE).
However, I do reset the AUTO_INCREMENT values by using an ALTER TABLE
command? Do all ALTER TABLE commands in MySQL imply a transaction
commit? Or does it depend on how you alter the table?

Caleb wrote:

Fred wrote:

The problem with mysql is that there are a bunch of statements that cause an
implicit commit and this list includes most of the things you do in a
migration: adding/removing indexes, ALTER TABLE, creating tables. So
even if you do wrap your migration in a transaction, just about anything
you do in your migration will commit the transaction.

Good point! Fortunately, I’m using these migrations to do data changes
(INSERT/UPDATE/DELETE), NOT SCHEMA changes (ALTER/DROP/CREATE).
However, I do reset the AUTO_INCREMENT values by using an ALTER TABLE
command? Do all ALTER TABLE commands in MySQL imply a transaction
commit? Or does it depend on how you alter the table?

Official docs are at
http://mysql.speedbone.de/doc/refman/5.0/en/implicit-commit.html they
seem to say that any ALTER TABLE statement will cause the implicit
commit

Fred

Caleb said:

I need to invoke Rake migrate from another class, not invoke a Rake task from
within a migration. Any idea as to why I’m getting the console error above?
I’d assume (maybe a poor assumption?) that once I can get it to work in the
Rails console then it should work from any line of code in my Rails app.

Anyone have any ideas on this?

For data-only modifications, you can use a simple transaction do
statement
like anywhere else:

class TransactionTest < ActiveRecord::Migration
def self.up
transaction do
execute “insert into some_table(some_column) values(‘some_value’)”
end
end

def self.down
end
end

For a cool slideshow that deals with this a little check out page 18 of:

http://www.chariotsolutions.com/slides/PhillyOnRails-Migrations.pdf

If you want to make the switch to a database that supports transactions
for
ddl (like postgres), you can also install this plugin and it should
solve
most of your problems:

http://www.redhillconsulting.com.au/rails_plugins.html#transactional_migrations

I haven’t tried that latest plugin, but I regularly use transaction do
for
my more complicated data manipulations scripts.

Jeff

On 10/2/06, Caleb [email protected] wrote:

Anyone have any ideas on this?


Posted via http://www.ruby-forum.com/.


Jeff Dean
917.414.7801