前回の話を受けて、Railsの場合はどうなのかを調べてみたいと思います。ターゲットはRails 2.3.5です。


RailsのO/R MapperはActiveRecordです。今回はActiveRecordでMySQLの場合について調べます。


def active? if @connection.respond_to?(:stat) @connection.stat else @connection.query 'select 1' end # mysql-ruby doesn't raise an exception when stat fails. if @connection.respond_to?(:errno) else true end rescue Mysql::Error false end

うぉ、SELECT 1とかそのままじゃないか。とりあえず次はこれを呼び出しているところを探します。するとconnection_adaptors/abstract_adaptor.rbの149行目にverify!(*ignored)メソッドがありました。

# Checks whether the connection to the database is still active (i.e. not stale). # This is done under the hood by calling active?. If the connection # is no longer active, then this method will reconnect to the database. def verify!(*ignored) reconnect! unless active? end


def checkout_and_verify(c) c.verify! c.run_callbacks :checkout @checked_out << c c end


def checkout_new_connection c = new_connection @connections << c checkout_and_verify(c) end def checkout_existing_connection c = (@connections - @checked_out).first checkout_and_verify(c) end


def checkout # Checkout an available connection @connection_mutex.synchronize do loop do conn = if @checked_out.size < @connections.size checkout_existing_connection elsif @connections.size < @size checkout_new_connection end return conn if conn # No connections available; wait for one if @queue.wait(@timeout) next else # try looting dead threads clear_stale_cached_connections! if @size == @checked_out.size raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it." end end end end end


# Retrieve the connection associated with the current thread, or call # #checkout to obtain one if necessary. # # #connection can be called any number of times; the connection is # held in a hash keyed by the thread id. def connection if conn = @reserved_connections[current_connection_id] conn else @reserved_connections[current_connection_id] = checkout end end # Signal that the thread is finished with the current connection. # #release_connection releases the connection-thread association # and returns the connection to the pool. def release_connection conn = @reserved_connections.delete(current_connection_id) checkin conn if conn end # Reserve a connection, and yield it to a block. Ensure the connection is # checked back in when finished. def with_connection conn = checkout yield conn ensure checkin conn end

とまあだいたいこんな感じで、ActiveRecord::Base.connection.execute("SELECT * FROM users")が実行されるときには、active?メソッドが呼び出されているわけです。実際に、例えばp "Active Check!"なんてのを仕込むと毎回表示されます。これはproduction環境でも変わりませんでした。


comments powered by Disqus