解決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查詢不到表中最新插入的數據的問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM