使用带有 mysql 连接器的自定义上下文管理器类时如何提交或回滚数据库中的更改

问题描述 投票:0回答:1

通过自定义上下文管理器类使用 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()

忽略错误处理方面的不良实践,提交和回滚是否会按预期工作,还是必须以不同的方式组织它?

编辑

上述模式似乎按预期工作(如果测试,则回滚,如果没有则提交,如果异常则回滚)。我不完全确定为什么,所以在这方面的任何启发都会有所帮助。谢谢!

python commit mysql-connector rollback contextmanager
1个回答
0
投票

它之所以有效,是因为您编写它是为了处理所有可能性。然而,奇怪的是您没有使用在上下文管理器中创建的对象。

考虑可能性:

1.测试成功:
执行

commit
。 (如果提交抛出异常,它将在您的提交函数中捕获并处理)
2. 测试失败:
执行
rollback
。 (但请注意,您是在上下文管理器之外完成此操作,这有点奇怪,因为连接(至少对于光标)已关闭)
3.抛出异常:
捕获异常并执行回滚。

所以所有案件都得到处理。需要注意的一件事是,您可能想要记录一些内容,让用户知道您未能提交并执行了回滚。
还值得注意的是,以下语法: 如果您想像在下一行中那样使用上下文管理器,那么

database_connection = DatabaseConnection(...)
我没有意义。您应该能够将这两行压缩为简单的
with DatabaseConnection(...) as cursor:
,然后用
database_connection
替换上下文管理器中
cursor
的用法。这就是首先使用上下文管理器的要点。不要在与数据库具有“相同”连接的两个不同对象之间进行混合和匹配,其中一个对象是上下文管理的,而另一个对象不是。这是糟糕的编码,而且非常不符合 Python 标准,并且可能会产生非常意外的结果。

这提出了 @snakecharmerb 的观点,即您应该考虑将回滚放入

__exit__
代码中。就目前情况而言,您基本上没有使用上下文管理器。

© www.soinside.com 2019 - 2024. All rights reserved.