From: Mike Bayer Date: Wed, 13 Jan 2010 20:42:09 +0000 (+0000) Subject: local session caching example X-Git-Tag: rel_0_6beta1~74 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6e6b13b945299aede8bade024403d74af43279db;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git local session caching example --- diff --git a/examples/beaker_caching/README b/examples/beaker_caching/README index 1eb93f8734..702690036f 100644 --- a/examples/beaker_caching/README +++ b/examples/beaker_caching/README @@ -30,6 +30,8 @@ Three endpoint scripts, in order of complexity, are run as follows: python examples/beaker_caching/advanced.py + python examples/beaker_caching/local_session_caching.py + Listing of files: @@ -53,3 +55,8 @@ relation endpoints, so that lazyloads load from cache. advanced.py - Further examples of how to use FromCache. Combines techniques from the first two scripts. + +local_session_caching.py - Grok everything so far ? This example +creates a new Beaker container that will persist data in a dictionary +which is local to the current session. remove() the session +and the cache is gone. \ No newline at end of file diff --git a/examples/beaker_caching/local_session_caching.py b/examples/beaker_caching/local_session_caching.py new file mode 100644 index 0000000000..c422600d87 --- /dev/null +++ b/examples/beaker_caching/local_session_caching.py @@ -0,0 +1,95 @@ +"""local_session_caching.py + +Create a new Beaker cache type + a local region that will store +cached data local to the current Session. + +This is an advanced example which assumes familiarity +with the basic operation of CachingQuery. + +""" + +from beaker import cache, container +import collections + +class ScopedSessionNamespace(container.MemoryNamespaceManager): + """A Beaker cache type which will cache objects locally on + the current session. + + When used with the query_cache system, the effect is that the objects + in the cache are the same as that within the session - the merge() + is a formality that doesn't actually create a second instance. + This makes it safe to use for updates of data from an identity + perspective (still not ideal for deletes though). + + When the session is removed, the cache is gone too, so the cache + is automatically disposed upon session.remove(). + + """ + + def __init__(self, namespace, scoped_session, **kwargs): + """__init__ is called by Beaker itself.""" + + container.NamespaceManager.__init__(self, namespace) + self.scoped_session = scoped_session + + @classmethod + def create_session_container(cls, beaker_name, scoped_session): + """Create a new session container for a given scoped_session.""" + + def create_namespace(namespace, **kw): + return cls(namespace, scoped_session, **kw) + cache.clsmap[beaker_name] = create_namespace + + @property + def dictionary(self): + """Return the cache dictionary used by this MemoryNamespaceManager.""" + + sess = self.scoped_session() + try: + nscache = sess._beaker_cache + except AttributeError: + sess._beaker_cache = nscache = collections.defaultdict(dict) + return nscache[self.namespace] + + +if __name__ == '__main__': + import __init__ # if running as a script + import meta + + # create a Beaker container type called "ext:local_session". + # it will reference the ScopedSession in meta. + ScopedSessionNamespace.create_session_container("ext:local_session", meta.Session) + + # set up a region based on this new container type. + meta.cache_manager.regions['local_session'] ={'type':'ext:local_session'} + + from model import Person + + # query to load Person by name, with criterion + # of "person 10" + q = meta.Session.query(Person).\ + options(meta.FromCache("local_session", "by_name")).\ + filter(Person.name=="person 10") + + # load from DB + person10 = q.one() + + # next call, the query is cached. + person10 = q.one() + + # clear out the Session. The "_beaker_cache" dictionary + # disappears with it. + meta.Session.remove() + + # query calls from DB again + person10 = q.one() + + # identity is preserved - person10 is the *same* object that's + # ultimately inside the cache. So it is safe to manipulate + # the not-queried-for attributes of objects when using such a + # cache without the need to invalidate - however, any change + # that would change the results of a cached query, such as + # inserts, deletes, or modification to attributes that are + # part of query criterion, still require careful invalidation. + cache, key = q._get_cache_plus_key() + assert person10 is cache.get(key)[0]