解决pymysql查不到最新数据的办法

最近用 Flask 写了几个接口部署在服务器上,然后用 Pytest 来做测试,但遇到了问题,搞了大半天才把问题解决。

问题场景及原因

问题大概是这样的,我在本地环境用 Pytest 写代码来对服务器上 Flask 的接口进行测试,在测试删除接口的时候,第一步我在 Pytest 中会通过SQL插入数据到MySQL数据库,第二步再调删除接口完成删除用户。最后执行 Pytest 代码没跑通过,会返回用户不存在,但这个情况到数据库里查看,发现该用户实际是存在于MySQL中。

首先,这个接口是没啥大问题的,调注册接口或手工插入数据,再手工请求访问接口可以正常完成删除,只是我在 Pytest 代码中通过SQL插入数据会出现这个问题。

其次,怀疑自己 Pytest 代码写得有问题,但检查后发现没问题,并且加了查询操作发现能查回这个新插入的数据。

最后,在各种排查后,在 Flask 接口服务中,也加了查询操作,但发现压根没查回这个新插入的数据。

于是,感觉接口环境下通过 Python 连接 pymysql ,查询数据库时,获取到的似乎似乎不是最新数据,所以调用户删除接口才会提示用户不存在。接着,在网上查了下资料,发现是事务的隔离级别导致的这个问题。

MySQL默认事务隔离级别是 REPEATABLE READ,当我在本地 Pytest 代码中利用SQL插入用户数据并提交 commit 后,接口环境下的事务A不会读取到我本地环境下的事务B更新的信息,即便事务B已提交,而事务A每次查询到的数据都是最开始创建事务查询到结果的快照,事务A一直没进行更新。

更详细的解释说明,可参考文末列出的网上资料。

问题代码

import pymysql

class MysqlDb():

    def __init__(self, host, port, user, passwd, db):
        # 建立数据库连接
        self.conn = pymysql.connect(
            host=host,
            port=port,
            user=user,
            passwd=passwd,
            db=db
        )
        # 通过 cursor() 创建游标对象,并让查询结果以字典格式输出
        self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    def __del__(self): # 对象资源被释放时触发,在对象即将被删除时的最后操作
        # 关闭游标
        self.cur.close()
        # 关闭数据库连接
        self.conn.close()

    def select_db(self, sql):
        """查询"""
        # 检查连接是否断开,如果断开就进行重连
        self.conn.ping(reconnect=True)
        # 使用 execute() 执行sql
        self.cur.execute(sql)
        # 使用 fetchall() 获取查询结果
        data = self.cur.fetchall()
        return data

    def execute_db(self, sql):
        """更新/新增/删除"""
        try:
            # 检查连接是否断开,如果断开就进行重连
            self.conn.ping(reconnect=True)
            # 使用 execute() 执行sql
            self.cur.execute(sql)
            # 提交事务
            self.conn.commit()
        except Exception as e:
            print("操作出现错误:{}".format(e))
            # 回滚所有更改
            self.conn.rollback()

解决办法

根据以上说明,要解决当前这个问题,我们可以通过以下方式来处理。

方法1:修改MySQL的事务隔离级别
方法2:每次查询操作后,都进行 commit() 提交事务。
方法3:Python创建pymysql连接时,设置 autocommit=True ,即让其操作后自动提交事务。

在这里,我们最好在方法2和方法3任选一个方法来处理就行了,不建议去修改MySQL的事务隔离级别。

  • 每次查询后进行提交事务
    def select_db(self, sql):
        """查询"""
        # 检查连接是否断开,如果断开就进行重连
        self.conn.ping(reconnect=True)
        # 使用 execute() 执行sql
        self.cur.execute(sql)
        # 使用 fetchall() 获取查询结果
        data = self.cur.fetchall()
        # 提交事务
        self.conn.commit()
        return data
  • 设置 autocommit=True 自动提交事务
    def __init__(self, host, port, user, passwd, db):
        # 建立数据库连接
        self.conn = pymysql.connect(
            host=host,
            port=port,
            user=user,
            passwd=passwd,
            db=db,
            autocommit=True
        )
        # 通过 cursor() 创建游标对象,并让查询结果以字典格式输出
        self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

使用以上方法后,再次测试,发现问题已顺利得到解决。

参考资料:
为什么pymysql重连后才能查到被其他地方修改的数据 pymysql缓存?
记一次pymysql查询不到表中最新插入的数据的问题

猜你喜欢

转载自www.cnblogs.com/wintest/p/12825371.html
今日推荐