提问人:Philip09 提问时间:8/22/2023 最后编辑:UpAndAdamPhilip09 更新时间:8/24/2023 访问量:81
在将自定义上下文管理器类与 mysql 连接器一起使用时如何提交或回滚数据库中的更改
How to commit or rollback a change in database when using a custom context manager class with mysql connector
问:
通过自定义上下文管理器类使用 mysql 连接器时,处理提交或回滚数据库中更改的最佳方法是什么?例如,假设自定义类采用以下形式:
class DatabaseConnection:
def __init__(self, host, user, password, database_name)
self.host = host
self.user = user
self.passwd = password
self.database_name = database_name
self.connection = None
def __enter__(self) -> Union[mysql.cursor.MySQLCursor, None]:
try:
if self.connection is None or not sef.connection.is_connected():
self.connection = mysql.connect(
host = self.host, user=self.user, psswd=self.psswd, db=self.database_name
)
cursor = self.connection.cursor()
return cursor
except Exception:
return None
def __exit__(self, exc_type, exc_val, exc_tb):
if self.connection is not None:
self.connection.close()
def commit(self):
if self.connection is not None and self.connection.is_connected():
try:
self.connection.commit()
return True
except:
self.connection.rollback()
def rollback(self):
if self.connection is not None:
self.connection.rollback()
然后你想使用它,使用语句,这样你就有了光标。您将如何管理提交或回滚更改,尤其是在引发错误时。例如:with
test = True
database_connection = DatabaseConnection(....)
try:
with database_connection() as cursor:
# perform some operations
if test:
database_connection.rollback()
else:
database_connection.commit()
except Exception as e:
database_connection.rollback()
忽略错误处理方面的不良做法,提交和回滚是否按预期工作,或者您是否必须以不同的方式组织它?
编辑
上述模式似乎按预期工作(如果测试,则回滚,如果不是,则提交,如果异常,则回滚)。我不完全确定为什么,所以在这方面的任何启示都会有所帮助。谢谢!
答:
它之所以有效,是因为您已经编写了它来处理所有可能性。然而,奇怪的是,您没有使用在上下文管理器中创建的对象。
考虑以下可能性:
1.测试成功:
执行。(如果 commit 抛出异常,它将在您的 commit 函数中被捕获和处理)
2. 测试失败:
执行。(请注意,您是在上下文管理器之外执行此操作的,这有点奇怪,因为连接(至少对于光标)已关闭)
3. 抛出异常:
捕获异常并执行回滚。commit
rollback
因此,所有案件都得到了处理。需要注意的一点是,您可能希望记录一些内容,以便让用户知道您未能提交并执行了回滚。
同样值得注意的是,如果要像在下一行中那样使用上下文管理器,则语法没有意义。您应该能够将这两行压缩为简单,然后将上下文管理器中的用法替换为 。这就是首先使用上下文管理器的重点。不要在两个不同的对象之间混合和匹配,这两个对象与数据库的“相同”连接,其中一个是上下文管理的,另一个不是。这是糟糕的编码,而且非常不谒蛇,可能会产生非常意想不到的结果。database_connection = DatabaseConnection(...)
with DatabaseConnection(...) as cursor:
database_connection
cursor
然后,这就提出了@snakecharmerb的观点,即您应该考虑将回滚放入代码中。就目前而言,您基本上没有使用上下文管理器。__exit__
评论
host
user
password
databasename
cursor
#perform some operations
if test: database_connection.rollback()
if test: cursor.rollback()
__exit__
评论
commit
__exit__
if ... else ...