diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index cf697e7515387..e61c78bb5e2fd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -129,7 +129,14 @@ def query_cache_enabled end def clear_query_cache - query_cache.clear + if @pinned_connection + # With transactional fixtures, and especially systems test + # another thread may use the same connection, but with a different + # query cache. So we must clear them all. + @thread_query_caches.each_value(&:clear) + else + query_cache.clear + end end private diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index a90b5147f10a3..9535b13d1fe8e 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -672,6 +672,40 @@ def test_clear_query_cache_is_called_on_all_connections end end + test "query cache is cleared for all thread when a connection is shared" do + ActiveRecord::Base.connection_pool.pin_connection!(ActiveSupport::IsolatedExecutionState.context) + + begin + assert_cache :off + ActiveRecord::Base.connection.enable_query_cache! + assert_cache :clean + + Post.first + assert_cache :dirty + + thread_a = Thread.new do + middleware { |env| + assert_cache :dirty # The cache is shared with the main thread + + Post.first + assert_cache :dirty + + Post.delete_all + + assert_cache :clean + + [200, {}, nil] + }.call({}) + end + + thread_a.join + + assert_cache :clean + ensure + ActiveRecord::Base.connection_pool.unpin_connection! + end + end + private def with_temporary_connection_pool(&block) pool_config = ActiveRecord::Base.connection.pool.pool_config