更新数据库中的行没有效果

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

我正在构建一个 python 应用程序,其目的是循环轮询 Microsoft SQL Server 数据库(每 100-200 毫秒)以获取 STATUS = 10 的新行。 当查询有结果时,应立即设置STATUS = 15,并根据查询到的数据进行处理。数据处理后,它应该将状态更新为 20。第二个描述的更新发生在另一个线程中,该线程与同一 SQL Server 有单独的连接。

实施:

选择并更新至状态 15:

def _pop_from_db(self):
    if self.db_connection: # connection was established with self.db_connection = pyodbc.connect("connection_string)
        oldest_update_datum_allowed = self.start_up_time_from_db_server + timedelta(minutes=0)
        try:
            with self.db_connection.cursor() as cursor:
                cursor.execute(

                    """
                    SELECT TOP 1 Id, Number, Status FROM table
                    WHERE UpdateDatum > ? AND Status = ? ORDER BY Id
                    """,
                    [oldest_update_datum_allowed, 10])

                row = cursor.fetchone()
                columns = [column[0] for column in cursor.description]
                if row:
                    m = dict(zip(columns, row))
                    cursor.execute(
                        """
                        UPDATE table SET Status=? WHERE Id=?
                        """,
                        [15, m["Id"]]
                    )
                    self.db_connection.commit()
                    rowcount = cursor.rowcount
                    logging.debug(f"Successfully updated Status for id {m['Id']} to {15} (rowcount {rowcount}).")
                    return m
                return None
        except pyodbc.Error as e:
            logging.error(traceback.format_exc())
            logging.error("Error while querying db. Wait 1 second and try to reconnect")
            sleep(1)
            self._connect_db_server()
            return None
    else:
        logging.error(f"No db connection. Wait 1 second and try to reconnect")
        sleep(1)
        self._connect_db_server()
    return None

更新到状态20(不同类和不同线程):

            try:
                with self.db_connection2.cursor() as cursor:
                    cursor.execute(
                        """
                        UPDATE table SET Status=?, WHERE Id=?;
                        """,
                        [20, id]
                    )
                    self.db_connection2.commit()
                    rowcount = cursor.rowcount
                    logging.debug(f"Successfully updated Status for id {id} to {20} (rowcount {rowcount}).")
            except pyodbc.OperationalError as e:
                logging.error(f"Exception while updating status for id {id} to {20}.")
                self._connect_db_server()

问题:

更新状态并不总是有效。
大约有二百次之一的情况下,两种状态更新之一都不起作用。我的应用程序代码中没有收到任何错误消息或异常。而且返回的cursor.rowcount 始终为1。但在数据库中没有任何变化。状态保持更新声明之前的状态。

有什么想法吗,这种奇怪的行为可能来自哪里?关于如何改进实施有什么建议吗?

编辑:

数据库表定义了一些触发器。当状态发生变化时,这些会更新更新行的时间戳字段。

编辑2:

我尝试了不同的方法,例如在中央线程上同步所有查询,并在更新到 15 时仅更新状态为 10 的情况,在更新到 20 时更新状态为 15 的情况......但没有任何效果。
然后我使用了 SQL Server Management Studio 中的 SQL Server Profiler。我在那里过滤了给定表中的更新。即使发生错误,我也可以看到所有更新都正常工作。
因此,从分析器视图来看,更新似乎有效。
我明白了

SQL:BatchCompleted

但在表中,数据没有更新。

问题:SQL Profiler 有没有办法查看是否有回滚发生?

python sql-server pyodbc
1个回答
0
投票

因此,经过一番艰苦的研究,我在这里找到了有关情况的更多详细信息以及我希望的(最终)解决方案:

前面几句话:
SQL Server 实例不在我的控制之下。该表不是由以下人员创建和配置的。它由另一家公司控制。这是另一家公司提出的接口,我必须将其实现到我的软件中。

我做了什么:

为了获得有关正在发生的事情的更多详细信息,我决定使用 SQL Profiler(我猜更现代的方法是 SQL Server 中的扩展事件。但是我必须处理的 SQL Server 实例是没有扩展的旧版本)活动)。
在弄清楚如何过滤服务器上发生的大量消息(这是控制生产的工厂中非常繁忙的 SQL Server 实例)之后,我找到了一个设置,它为我提供了更多信息。

我发现了什么:

在 SQL Profiler 中,每个更新查询均使用

SQL:BatchStarting
SQL:BatchCompleted
进行记录。他们之间总是发生事务(开始和提交)。在 UPDATE 查询未按预期工作的情况下,我注意到这些事务的事务回滚。
我想在没有 SQL 事务的情况下工作,所以我在
pyodbc
中设置了 autocommit = True。交易量减少了,我感觉错误发生的次数比以前少了。但有时在
SQL:BatchStarting
SQL:BatchCompleted
之间的事务回滚中仍然会发生这种情况。
我更深入地研究了数据库和表配置。我注意到为表定义了一些触发器。该触发器将一些日志记录到另一个表中。在触发器结束时,有一条语句删除了 x 天之前的日志消息。我的猜测:此删除可能会导致某种阻塞,也可能导致事务回滚。

解决方案

我禁用了插入日志表并删除旧日志消息的触发器。这似乎解决了问题。系统现已运行超过 36 小时,更新状态超过 30,000 次,没有出现任何错误。
我不知道为什么

SQL:BatchStarting
SQL:BatchCompleted
之间仍然存在SQL事务。但我对结果很满意。

结论

最终这不是 pyodbc、python 或我糟糕的实现的问题。错误发生在服务器端。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.