如果没有在连接池上手动调用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
答案 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
,但是同时连接池本身仍应完全可用于其他线程(除非线程多于配置的连接在池中 - 尝试检索新连接的线程必须等到其他一些线程完成其工作。)