Forum: Ruby on Rails Caching of database values

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
7b74ccf93dde7dd2ac5d2980d14fdc7b?d=identicon&s=25 Paul Lynch (plynchnlm)
on 2007-04-21 00:26
(Received via mailing list)
If do something like this:
    dbObj = MyTable.find_by_id(5)
    a = dbObj.name
    b = dbObj.name

How many times will an SQL call be made to get the value of
MyTable.name for id 5?  In other words, are the values for dbObj
cached in the object?  Is there a way of controlling that?  (I can
imagine that sometimes you might not want to cache them if you wanted
to be sure of having the latest value.)

Thanks,
     --Paul
8da92d4ed91aa12535f6d870fa76b25e?d=identicon&s=25 Aaron (Guest)
on 2007-04-21 00:49
(Received via mailing list)
Only one db query is performed.  The result is stored in your dbObj
variable.  If you want to "refresh" your in memory copy call reload:

dbObj.reload

A good way to monitor what rails is doing on the back end is to run a
tail -f on the log.  You'll see every sql query and result.

Aaron
888e0536d537efdd327f3a1c39335e4c?d=identicon&s=25 Christos Zisopoulos (Guest)
on 2007-04-21 16:02
(Received via mailing list)
Hello Paul,

You are indeed correct; all results from the find are cached in
memory as attributes of the MyTable object.

I believe ActiveRecord gives you an option to achieve what you want
through the use of transactions and locking. You can do the following:

MyTable.transaction do
   dbObj = MyTable.find_by_id(5, :lock => true)
   a = dbObj.name
   b = dbObj.name
end

The above will ensure that you get an exclusive lock to the table/row
you want to work with, inside the transaction block. No other process
will get access to that row until your transaction is finished.

If you don't want to lock the row (or table depending on the DB you
use) then you can use optimistic locking. Optimistic locking makes
sure that you can not save stale data to the DB. It doesn't help with
reading of stale data though.

Put the following 'special' column in your migrations for MyTable:

   t.column :lock_version, :integer, :default => 0

The version number is automagically incremented on every save by
Rails. If your lock_version is out of sync with that of the DB, i.e.
someone else has updated your record while you had it in memory, then
you get an exception.

As a final solution you could write attribute accessors for your
model that force the object to reload itself every time you access
the data. It is not a 100% guarantee of freshness (and it will floor
your DB), but it works. For example:

class MyTable < ActiveRecord::Base
   def name
     self.reload
     read_attribute(:name)
   end
end

Hey, you can even make it into a plugin so you can do:

class MyTable < ActiveRecord::Base
   acts_as_nearly_fresh :name, :title, :address
end

(I'll leave the plugin implementation to you; I find naming act_as_*
plugins more fun than writing them)

Hope this helps,

-christos
This topic is locked and can not be replied to.