了解establish_connection如何在ActiveRecord中工作

时间:2022-02-12 18:55:26

This code was taken from ActiveRecord 2.3.14's gem class ConnectionHandler

此代码取自ActiveRecord 2.3.14的gem类ConnectionHandler

def establish_connection(name, spec)
  @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
end

It seems each time ruby calls establish_connection on the model, it's creating a new connection pool.

似乎每次ruby在模型上调用establish_connection时,它都会创建一个新的连接池。

My question:

我的问题:

If I have 5 models that use establish_connection to the same database, is Rails smart enough to pick an already existing pool rather creating a new one with the same connection credentials? Does this also happen if my 5 models are subclasses of some abstract class that uses establish_connection? Will it always pick a connection from the @connection_pools if it exists?

如果我有5个使用establish_connection到同一个数据库的模型,那么Rails是否足够智能选择一个已经存在的池而不是创建一个具有相同连接凭据的新池?如果我的5个模型是使用establish_connection的某个抽象类的子类,这是否也会发生?如果它存在,它总是会从@connection_pools中选择一个连接吗?

Update 1

更新1

I'm talking about a concrete example. You have 5 models with 5 different connections, each time Rails uses a model it executes establish_connection. Looking at the code in ActiveRecord, when it executes establish_connection it creates a new pool with connections to that specific connection. What I'm wondering is whether each time Rails calls a model's establish_connection, does it create a new pool or take the existing one.

我在谈论一个具体的例子。你有5个模型,有5个不同的连接,每次Rails使用它执行establish_connection的模型。查看ActiveRecord中的代码,当它执行establish_connection时,它会创建一个与该特定连接有连接的新池。我想知道的是,每次Rails调用模型的establish_connection时,它是创建新池还是采用现有池。

Example: you come to my site and see a product list. You've just hit an action that calls Product.all, which executes establish_connection to some database on Amazon. Then, I come to the product list, what happens? Do I grab the established connection or am I creating a new pool with that connection?

示例:您访问我的网站并查看产品列表。您刚刚点击了一个名为Product.all的动作,该动作执行了对亚马逊某些数据库的establish_connection。然后,我来到产品列表,会发生什么?我是否已获取已建立的连接,或者是否正在创建具有该连接的新池?

Update 2

更新2

My guess is that first time Rails loads my models it's creating pools with different connections. After, when I use some Model.method, it just grabs the connection associated with the model and executes the method.

我的猜测是,第一次Rails加载我的模型,它创建了具有不同连接的池。之后,当我使用一些Model.method时,它只是抓取与模型关联的连接并执行该方法。

I'm not sure what happens when 2 models have two equal connections (not in the abstract class but in self class). Will this produce two same connection pools, or is ActiveRecord smart enough to catch this case?

我不确定当2个模型有两个相等的连接时会发生什么(不是在抽象类中而是在自习类中)。这会产生两个相同的连接池,还是ActiveRecord足够智能来捕捉这种情况?

3 个解决方案

#1


8  

You really do not have to call establish_connection on each model. You can simply do next:

您真的不必在每个模型上调用establish_connection。你可以简单地做下一个:

ActiveRecord::Base.establish_connection(
 { :adapter => 'mysql2',
   :database => 'some_database',
   :host => 'localhost',
   :username => 'root',
   :password => "" }
)

and you will have access to connection. (This chunk of code has been extracted from real code(except database name :) )).
But according to API I think that Rails does not take existing connection from other model (correct me if I am wrong).
Also here is a link to documentation. You can read more about the connection there.
I hope I helped you alittle.

并且您将有权访问连接。 (这段代码已从实际代码中提取(数据库名称除外:)))。但根据API,我认为Rails不会从其他模型中获取现有连接(如果我错了,请纠正我)。这里还有一个文档链接。您可以在那里阅读有关连接的更多信息。我希望我能帮助你。

#2


14  

AR calls establish_connection only once, for ActiveRecord::Base. All subclasses use the one connection.

对于ActiveRecord :: Base,AR只调用一次Establish_connection。所有子类都使用一个连接。

You can manually call establish connection yourself on some subclasses. This is very convenient for using two databases at once, e.g.

您可以在某些子类上自己手动调用建立连接。这对于一次使用两个数据库非常方便,例如:

class MyMainUser < ActiveRecord::Base; end 
class MyOtherDb < ActiveRecord::Base; end
class MyOtherUser < MyOtherDb; end

MyOtherDb.establish_connection ...

MyMainUser.first # uses default db
MyOtherUser.first # uses other db

You can't do queries that would cross databases though.

但是,您不能执行跨数据库的查询。

#3


2  

This comment:

这个评论:

# Check-out a database connection from the pool, indicating that you want
# to use it. You should call #checkin when you no longer need this.
#
# This is done by either returning an existing connection, or by creating
# a new connection. If the maximum number of connections for this pool has
# already been reached, but the pool is empty (i.e. they're all being used),
# then this method will wait until a thread has checked in a connection.
# The wait time is bounded however: if no connection can be checked out
# within the timeout specified for this pool, then a ConnectionTimeoutError
# exception will be raised.

from: https://github.com/rails/rails/blob/dd944cbf5879e675fff541d1be7c7eb6c3382d01/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L242-251

来自:https://github.com/rails/rails/blob/dd944cbf5879e675fff541d1be7c7eb6c3382d01/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L242-251

Should explain the situation

应该解释一下情况

#1


8  

You really do not have to call establish_connection on each model. You can simply do next:

您真的不必在每个模型上调用establish_connection。你可以简单地做下一个:

ActiveRecord::Base.establish_connection(
 { :adapter => 'mysql2',
   :database => 'some_database',
   :host => 'localhost',
   :username => 'root',
   :password => "" }
)

and you will have access to connection. (This chunk of code has been extracted from real code(except database name :) )).
But according to API I think that Rails does not take existing connection from other model (correct me if I am wrong).
Also here is a link to documentation. You can read more about the connection there.
I hope I helped you alittle.

并且您将有权访问连接。 (这段代码已从实际代码中提取(数据库名称除外:)))。但根据API,我认为Rails不会从其他模型中获取现有连接(如果我错了,请纠正我)。这里还有一个文档链接。您可以在那里阅读有关连接的更多信息。我希望我能帮助你。

#2


14  

AR calls establish_connection only once, for ActiveRecord::Base. All subclasses use the one connection.

对于ActiveRecord :: Base,AR只调用一次Establish_connection。所有子类都使用一个连接。

You can manually call establish connection yourself on some subclasses. This is very convenient for using two databases at once, e.g.

您可以在某些子类上自己手动调用建立连接。这对于一次使用两个数据库非常方便,例如:

class MyMainUser < ActiveRecord::Base; end 
class MyOtherDb < ActiveRecord::Base; end
class MyOtherUser < MyOtherDb; end

MyOtherDb.establish_connection ...

MyMainUser.first # uses default db
MyOtherUser.first # uses other db

You can't do queries that would cross databases though.

但是,您不能执行跨数据库的查询。

#3


2  

This comment:

这个评论:

# Check-out a database connection from the pool, indicating that you want
# to use it. You should call #checkin when you no longer need this.
#
# This is done by either returning an existing connection, or by creating
# a new connection. If the maximum number of connections for this pool has
# already been reached, but the pool is empty (i.e. they're all being used),
# then this method will wait until a thread has checked in a connection.
# The wait time is bounded however: if no connection can be checked out
# within the timeout specified for this pool, then a ConnectionTimeoutError
# exception will be raised.

from: https://github.com/rails/rails/blob/dd944cbf5879e675fff541d1be7c7eb6c3382d01/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L242-251

来自:https://github.com/rails/rails/blob/dd944cbf5879e675fff541d1be7c7eb6c3382d01/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L242-251

Should explain the situation

应该解释一下情况