我在使用 SQLAlchemy / Tastypie REST 界面插入数据库项时出现问题,但随后获取项列表时缺少该项。只有在我获得第二次的项目列表后才会显示。
我正在使用SQLAlchemy和Tastypie / Django通过mod_wsgi在Apache上运行。我使用单独的数据库管理器类来保存我的引擎和declarative_base,并使用Tastypie,一个单独的类来获取会话,并确保如果提交有问题我回滚。如下面的更新,插入后我不关闭我的会话时会出现问题。 为什么这有必要?
我的原始代码是这样的:
Session = scoped_session(sessionmaker(autoflush=True))
# Singleton Database Manager class for managing session
class DatabaseManager():
engine = None
base = None
def ready(self):
host='mysql+mysqldb://etc...'
if self.engine and self.base:
return True
else:
try:
self.engine = create_engine(host, pool_recycle=3600)
self.base = declarative_base(bind=self.engine)
return True
except:
return False
def getSession(self):
if self.ready():
session = Session()
session.configure(bind=self.engine)
return session
else:
return None
DM = DatabaseManager()
# A session class I use with Tastypie to ensure the session is destroyed at the
# end of the transaction, because Tastypie creates singleton Resources used for
# all threads
class MySession:
def __init__(self):
self.s = DM.getSession()
def safeCommit(self):
try:
self.s.commit()
except:
self.s.rollback()
raise
def __del__(self):
try:
self.s.commit()
except:
self.s.rollback()
raise
# ... Then ... when I get requests through Apache/mod_wsgi/Django/Tastypie
# First Request
obj_create():
db = MySession()
print db.s.query(DBClass).count() # returns 4
newItem = DBClass()
db.s.add(newItem)
db.s.safeCommit()
print db.s.query(DBClass).count() # returns 5
# Second Request after First Request returns
obj_get_list():
db = MySession()
print db.s.query(DBClass).count() # returns 4 ... should be 5
# Third Request is okay
obj_get_list():
db = MySession()
print db.s.query(DBClass).count() # returns 5
更新
进一步挖掘后,问题似乎是我的会话需要在创建后关闭。也许是因为Tastypie的object_create()将SQLAlchemy对象添加到它的bundle中,我不知道它离开函数范围后会发生什么:
obj_create():
db = MySession()
newItem = DBClass()
db.s.add(newItem)
db.s.safeCommit()
copiedObj = copyObj(newItem) # copy SQLAlchemy record into non-sa object (see below)
db.s.close()
return copiedObj
如果有人在回答中解释这一点,我可以提出问题。另外,对于那些好奇的人,我将我的对象从SQLAlchemy中复制出来:
class Struct:
def __init__(self, **entries):
self.__dict__.update(entries)
class MyTastypieResource(Resource):
...
def copyObject(self, object):
base = {}
# self._meta is part of my tastypie resource
for p in class_mapper(self._meta.object_class).iterate_properties:
if p.key not in base and p.key not in self._meta.excludes:
base[p.key] = getattr(object,p.key)
return Struct(**base)
答案 0 :(得分:0)
关闭我的会话解决了问题。答案中的更新并没有完全解决问题 - 我最终添加了一个中间件类来在事务结束时关闭会话。这确保了所有内容都写入数据库。中间件看起来有点像这样:
class SQLAlchemySessionMiddleWare(object):
def process_response(self, request, response):
try:
session = MyDatabaseManger.getSession()
session.commit()
session.close()
except Exception, err:
pass
return response
def process_exception(self, request, exception):
try:
session = MyDatabaseManger.getSession()
session.rollback()
session.close()
except Exception, err:
pass