SqlAlchemy:状态管理,如何在会话中持久化反序列化实例

时间:2016-04-14 07:33:01

标签: python sqlalchemy flask-sqlalchemy

简单的代码如:

import pickle, cPickle
from app import session, redis 

class MyObj(DeclarativeBase):
    @classmethod
    def get(cls,id):
       key = cls.__name__+":"+str(id)
       cached = redis.get(key)
       if cached:
          # unserialize to cls instance
          return cPickle.loads(cached)
       record = session.query(cls).filter(cls.id==id).one()
       if record:
          # serialize and store to redis
          redis.set(key, pickle.dumps(record))
       return record


# first time , a normal orm instance returned from session query (uncached)
obj = MyObj.get(1)

# but the next requests, get cached from redis.
# and i want to delete the record
delobj = MyObj.get(1)
session.delete(delobj)
session.commit()

它会引发错误,例如"实例xxx不会持久存在"

我在删除之前尝试了session.add(delobj),Pending状态为True(state = inspect(delobj)),但它仍然无法删除。

1 个答案:

答案 0 :(得分:0)

您需要merge缓存的实例到当前会话:

  

merge()将状态从外部对象传输到会话中的新实例或现有实例。

来自例子:

  

应用程序将对象存储在内存缓存中,同时由许多Session个对象共享。每次从缓存中检索对象时,都会使用merge(),以便在请求它的每个Session中创建它的本地副本。缓存的对象保持分离状态;只有它的状态被移动到各个Session对象本地的副本中。

     

在缓存用例中,通常使用load=False标志来消除协调对象状态与数据库的开销。还有一个名为merge()的{​​{1}}“批量”版本,旨在使用缓存扩展的查询对象 - 请参阅Dogpile Caching部分。

所以:

merge_result()

请记住仅缓存 if cached: # unserialize to cls instance return session.merge(cPickle.loads(cached), load=False) 的持久对象,否则您将收到错误:

cls

产生上述错误的简单方法:

InvalidRequestError: merge() with load=False option does not support objects transient (i.e. unpersisted) objects.  flush() all changes on mapped instances before merging with load=False.

另一方面,如果您首先正确地保留对象:

obj = MyObj()
cached = pickle.dumps(obj)
obj2 = session.merge(pickle.loads(cached), load=False)
 ...
InvalidRequestError: merge() with load=False option does not support objects transient (i.e. unpersisted) objects.  flush() all changes on mapped instances before merging with load=False.