11

我需要在我的 Rails 应用程序中执行一些原始 SQL。如果在事务中执行查询,它会导致隐式提交。我们将 MySQL 与 InnoDB 一起使用,查询将包括例如创建表。

执行查询ActiveRecord::Base.connection.execute会触发隐式提交,这是一个问题。

感觉就像我只需要一个单独的连接来执行我的查询。ActiveRecord 可以提供这个吗?我已经看到了关于连接到多个数据库但不是多个连接到同一个数据库的讨论。

如果有更好的方法,解决方案不必涉及 ActiveRecord。

我们的 Rails 和 ActiveRecord 版本是 3.2.3。

4

3 回答 3

20

数据库连接是在每个线程的基础上完成的(这基本上是线程安全所必需的),您可以利用它来发挥自己的优势:例如,只需在单独的线程中执行您的代码

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

从 rails 4 开始,activerecord 不再自动获取以这种方式创建的连接。为了避免泄漏连接,您需要将它们返回到池中。正如 Matt Connelly 建议的那样,最简单的方法是使用with_connection在块末尾检查连接的方法,例如

Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    ...
  end
end
于 2012-07-26T18:25:12.057 回答
4

重要的是,如果您在线程中使用连接,则在完成后将连接返回到连接池。最简单的方法是这样的:

Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do |connection|
    connection.execute "..." 
    # ensures the connection is returned to the pool when the thread is done.        
  end
end.join
于 2014-08-11T00:48:22.220 回答
2

DDl 和更多查询会触发隐式提交,因此它们不能按照 mysql 文档回滚

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html

这些隐式地结束当前会话中活动的任何事务,就像您在执行语句之前完成了 COMMIT 一样。

如果两者之间没有这样的查询,那么您可以使用 SAVEPOINT 功能。(这不适用于 DDL 语句

在活动记录中有一个选项可以帮助创建使用保存点的子事务

   ActiveRecord::Base.transaction do
     # ...
   ActiveRecord::Base.transaction(:requires_new => true) do #creates save point
       # perform task 
       # if error occurs rollbacks only till the save point.
     end
   end

查看Rails 文档以获取更多详细信息。

于 2012-07-26T18:16:46.683 回答