zoukankan      html  css  js  c++  java
  • 解决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查询不到表中最新插入的数据的问题

  • 相关阅读:
    完结篇《产品在路上》
    产品经理的七个层次
    互联网产品的交互设计
    互联网产品的用户体验
    用户体验设计 UED (下)
    用户体验设计 UED (上)
    【100Days of 100 line Code】1 day
    leetcode 392.判断子序列(Java 贪心)
    leetcode 605.种花问题(java 贪心)
    leetcode 122.买卖股票的最佳时机||(Java 贪心)
  • 原文地址:https://www.cnblogs.com/wintest/p/12825371.html
Copyright © 2011-2022 走看看