Action Pack请求中的Rails连接池循环相同的连接

时间:2016-03-29 03:03:45

标签: ruby-on-rails

如果没有在连接池上手动调用checkout / checkin,请求周期是否会使用单个连接进行串行请求?例如,给出以下代码段:

def show
  @user = User.find(...)
  @post = @user.posts.find(...)
  @blog = Blog.find(...)
  ...
end

每个生成的SQL调用(SELECT * FROM users ...SELECT * FROM posts ...SELECT * FROM blogs ...)是否可以保证在每种情况下使用相同的连接它是否可能checkout / checkin查询之间的新/旧连接?

此外 - 长时间运行的事务“阻止”连接池(假设只有在请求开始时没有结账并且在结束时签入时才会发生这种情况)?

User.transaction do
  @user.touch
  sleep 5
  @user.touch
end

VS

@user.touch
sleep 5
@user.touch

1 个答案:

答案 0 :(得分:0)

documentation on ConnectionPool表明与每个线程使用的数据库只有一个连接

让我深入研究Rails 4.2源代码以支持这一主张:

  • FinderMethods模块中定义的所有finder方法(例如Model.find(...))最终会在connection对象上调用一些查询方法。

  • connection模块中的ActiveRecord::Base.connection(也可以称为ConnectionHandling)为defined,它只调用ConnectionHandler retrieve a connection

  • ConnectionHandler,找到正确的数据库以获取连接(一个rails项目可能使用多个数据库),最后调用 connection method

此方法(如source code docs中所述)返回与当前线程关联的连接。在内部,它使用密钥为Thread.current.object_id的连接缓存,即当前线程的唯一ID。

因此,基于这些信息,我认为我们可以得出结论,除非您在代码中使用手动创建的线程,或者除非您自己检查了连接,否则给定模型/控制器中的串行查询应始终为调用与数据库的单一连接。并且他们不应该在您的查询之间签出/签入,因为线程通常在单个请求期间从不切换。

另一方面,使用不同线程到请求线程的所有代码部分将使用与池不同的连接。示例可能是后台作业,手动创建的线程或Puma application server的不同线程。

关于阻塞的第二个问题 - 长时间运行的查询肯定会阻止当前的connection,但是同时连接池本身仍应完全可用于其他线程(除非线程多于配置的连接在池中 - 尝试检索新连接的线程必须等到其他一些线程完成其工作。)