You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程下两个MySQL连接数据操作后无法同步更新的问题排查

问题分析与解决方案

核心原因

你的问题根源是MySQL事务隔离机制+未正确管理事务生命周期:
MySQL默认采用REPEATABLE READ(可重复读)隔离级别,在这个级别下,一个事务启动后会读取事务开始时的数据快照,后续其他连接提交的更新不会被当前事务感知,直到当前事务提交或回滚。而mysql.connector默认关闭了自动提交(autocommit=False),如果连接1执行SELECT后没有主动提交事务,就会一直停留在旧的数据快照中,看不到连接2的更新。

另外,你当前的代码存在严重的SQL注入漏洞,必须优先修复。

解决步骤

1. 开启自动提交或手动管理事务

方案一:全局开启自动提交

修改Database类的构造函数,在连接建立后开启自动提交,这样每个SQL语句执行后都会自动提交事务,不会保留旧快照:

class Database():
    def __init__(self):
        self.mydb = mysql.connector.connect(
            host=config.botConfig["host"],
            user=config.botConfig["user"],
            password=config.botConfig["password"],
            port=config.botConfig["port"],
            database=config.botConfig["database"],
            charset='utf8mb4'
        )
        self.mydb.autocommit = True  # 开启自动提交
        self.cursor = self.mydb.cursor()

        if self.mydb.is_connected():
            print("Database connection successful")
        else:
            print("Database connection failed")

方案二:手动提交事务

如果不想全局开启自动提交,确保连接1每次查询完成后提交事务,刷新数据快照:

# 连接1的查询示例
def get_world_data(self, idWorld):
    sql = "SELECT * FROM worlds_has_blocks WHERE idWorld = %s"
    self.cursor.execute(sql, (idWorld,))
    result = self.cursor.fetchall()
    self.mydb.commit()  # 提交事务,释放旧快照
    return result

2. 修复SQL注入漏洞

绝对不能用字符串拼接的方式构造SQL语句,改用参数化查询(mysql.connector用%s作为占位符):

def add_block_to_world(self, idWorld, idBlock, x, y):
    # 查询是否存在
    sql = "SELECT idRel FROM worlds_has_blocks WHERE idWorld = %s AND x = %s AND y = %s;"
    self.cursor.execute(sql, (idWorld, x, y))
    res = self.cursor.fetchone()
    
    if res:
        # 更新块
        sql = "UPDATE worlds_has_blocks SET idBlock = %s WHERE idWorld = %s AND x = %s AND y = %s;"
        self.cursor.execute(sql, (idBlock, idWorld, x, y))
    else:
        # 插入新块(注意VALUES是复数,你之前的拼写有误)
        sql = "INSERT INTO worlds_has_blocks VALUES(NULL, %s, %s, %s, %s);"
        self.cursor.execute(sql, (idWorld, idBlock, x, y))
    
    self.mydb.commit()

3. 多线程连接的正确性说明

你每个线程使用独立Database对象的做法是正确的——MySQL的连接对象不是线程安全的,跨线程共享单个连接会导致各种异常(比如你之前遇到的报错),所以每个线程维护自己的连接是标准的正确做法。


内容的提问来源于stack exchange,提问作者JanikCodes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:23:23