Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I execute a Database Operation outside of a transaction in Rails / ActiveRecord

I need to execute some raw SQL in my Rails app. The query will do cause an implicit commit if it is performed within a transaction. We are using MySQL with InnoDB and the query will include e.g. create table.

Executing the query with ActiveRecord::Base.connection.execute triggers the implict commit which is a problem.

It feels like I just need a separate connection for performing my queries. Can ActiveRecord provide this? I've seen discussions of connecting to multiple databases but not multiple connections to the same database.

A solution doesn't have to involve ActiveRecord if there's a better way.

Our Rails and ActiveRecord version is 3.2.3.

like image 690
matthewSpleep Avatar asked Jul 26 '12 17:07

matthewSpleep


People also ask

What is ActiveRecord base transaction in rails?

Transactions in ActiveRecordEvery database operation that happens inside that block will be sent to the database as a transaction. If any kind of unhandled error happens inside the block, the transaction will be aborted, and no changes will be made to the DB.

What does ActiveRecord base do?

ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending. Edit: as Mike points out, in this case ActiveRecord is a module...

Is ActiveRecord an ORM?

ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code.


1 Answers

Database connections are done on a per thread basis (this is basically required for thread safety), which you can use to your advantage: just execute your code in a separate thread, for example

ActiveRecord::Base.transaction do
  # ...
  Thread.new do
    ActiveRecord::Base.connection.execute "..." # in a new connection
  end.join
end

As of rails 4, activerecord no longer reaps connections created in this way automatically. To avoid leaking connections you need to return them to the pool. As Matt Connelly suggests, the easiest way to do this is to use the with_connection method which will check the connection back in at the end of the block, for example

Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    ...
  end
end
like image 182
Frederick Cheung Avatar answered Sep 18 '22 23:09

Frederick Cheung