问题描述
对于我的存储库类,我在有功能需要时(如果没有)创建与数据库的连接。如果不是“无”,我正在使用__del__
关闭连接。该对象保证寿命很短。
我意识到我依赖于Ref来尽快关闭连接。我需要将连接作为类中的一个字段,因为我正在做select for update
。我阅读的默认python gc至少引用了cpython实现。但是pypy实现具有许多不同类型的garbage collectors。可以依靠引用计数gc尽快关闭连接吗?还是应该编写一个单独的函数并使用try finally块确保关闭连接?
该类仅包含连接字段和两个函数,一个用于将表锁定在数据库中并选择值,另一个用于更新它们。
这是我当前的实现方式:
class ReserveRepository:
def __init__(self):
self.conn = None
def select(self):
cur = None
try:
self.conn = psycopg2.connect(config.DATABASE_URL)
cur = self.conn.cursor()
cur.execute('lock table soMetable in ACCESS EXCLUSIVE mode')
cur.execute('select id from soMetable where condition')
return list(map(lambda x: x[0]))
finally:
if cur is not None:
cur.close()
def update_quantities(self,id):
cur = None
try:
if self.conn is None:
self.conn = psycopg2.connect(config.DATABASE_URL)
cur = self.conn.cursor()
cur.execute('update soMetable set column1 = value where id = %s',(id,))
self.conn.commit()
return reservation_id
finally:
if cur is not None:
cur.close()
def __del__(self):
if self.conn is not None:
self.conn.close()
self.conn = None
解决方法
tldr; 答案是否定。据我了解,Pypy没有实现引用计数。为了演示这一点,我编写了一个简单的程序:
class Test:
def __init__(self):
print('__init__')
def __del__(self):
print('__del__')
t = Test()
print(t)
CPython 3.8.2的输出是:
__init__
<__main__.Test object at 0x7f6e3bc13dc0>
__del__
但是,Pypy 7.3.1(Python 3.6.9)的输出是
__init__
<__main__.Test object at 0x00007f58325dfe88>
未调用__del__
函数。
即使在CPython上,答案也是否。如果对象附加到了一个长期存在的缓存实例,则__del__
将永远不会被调用。更好的设计模式是为您的对象使用上下文管理器,并在__exit__
处进行清理:
with make_a_connection(parameter) as conn:
useconn(conn)