Python中while循环检查数据库字段改变,为何不重新初始化连接就查不到最新数据?

我是用的 pymysql 这个库,大体的代码逻辑如下:

...
做了一些事情,这些事情会导致数据库某个字段的值会改变
...

a=usermysql() # 自定义类的 __init__方法,pymysql.connect 和创建 cursor while True: a.execute() result = a.fetchone() if result == ‘WORKING’: # 执行语句,获取需要的字段的值,如果值变成了想要的,就退出循环,做接下来的任务 break

然而运行的时候,发现获取到的字段的值并不会变化,只有在 while 循环里初始化数据库的连接,才能获取到最新的数据库的值

请问这是为什么呢?


Python中while循环检查数据库字段改变,为何不重新初始化连接就查不到最新数据?

7 回复

数据库配置记录所有的查询,查看数据库 log 看请求有没有被数据库处理。
没有的话,查 execute 的文档,看是不是使用了类似执行过就不执行的机制。


这个问题很典型,是因为数据库连接池或事务隔离级别导致的。

简单说,你第一次执行查询时,连接可能开启了一个事务(取决于数据库驱动和配置,比如MySQL的默认隔离级别是“可重复读”)。在这个事务里,后续的查询看到的都是事务开始时的“快照”数据,即使数据库里实际数据已经变了,你这个连接里也看不到。

所以你的while循环一直在用同一个连接/事务,自然查不到其他会话提交的新数据。

要解决这个问题,最直接的办法就是在每次循环查询前,提交当前事务并开始一个新事务。对于大多数数据库驱动,执行一个SELECT查询也会隐式地开始一个事务。你需要显式地结束它。

这里给你一个使用mysql-connector-python的示例,其他数据库(如psycopg2sqlite3)原理类似,具体方法可能稍有不同(比如用autocommit模式)。

import mysql.connector
import time

def monitor_database_change():
    # 1. 建立连接
    conn = mysql.connector.connect(
        host="your_host",
        user="your_user",
        password="your_password",
        database="your_db"
    )
    cursor = conn.cursor()

    # 关键点:设置自动提交为True。这样每次查询后都会自动提交事务,
    # 下次查询就是一个新事务,能看到最新的提交。
    conn.autocommit = True

    # 或者,如果你不想用autocommit,可以在循环里手动提交:
    # conn.start_transaction(isolation_level='READ COMMITTED') # 也可以设置隔离级别

    last_value = None
    query = "SELECT your_field FROM your_table WHERE your_condition"

    try:
        while True:
            cursor.execute(query)
            current_value = cursor.fetchone()[0]  # 假设查询返回单个值

            if current_value != last_value:
                print(f"数据发生变化: {last_value} -> {current_value}")
                last_value = current_value
                # 这里可以触发你的业务逻辑

            time.sleep(1)  # 每秒检查一次

            # 如果没用autocommit,就在这里手动提交并开始新事务
            # conn.commit()

    except KeyboardInterrupt:
        print("监控停止")
    finally:
        cursor.close()
        conn.close()

if __name__ == "__main__":
    monitor_database_change()

核心就两点:

  1. 设置autocommit=True:这是最简单粗暴的方法,让每次查询独立。
  2. 使用READ COMMITTED隔离级别:如果你需要保持事务但又能看到最新提交,可以在创建连接或开始事务时指定更宽松的隔离级别(如READ COMMITTED),而不是默认的REPEATABLE READ

总结: 循环里查不到新数据是因为事务快照,让每次查询都开新事务就能解决。

仅仅从你 po 的这段 snippet 并不能看出问题,上源码链接吧

理论上,同一个语句,不同时候执行,返回的结果应该都是数据库里边最新的数据是吗?

"MVCC"

开启 autocommit,或者每次查完 commit。

能不能详细给讲一下呢?

pymysql 默认的 autocommit 是 false,不 commit 是不能查询到新的数据的,你可以设置为 true 或者每次查询完 commit

回到顶部