問題
- 首先自己寫了個事務內執行多個sql的包裝函數,使得這些sql的操作具有原子性,中間任意一條操作出現錯誤都會拋出異常並回退。
# 更新數據,可以執行數據的增、刪、改
...
def update_data(self, sqls: list):
connect = self.__get_connect()
cursor = connect.cursor()
try:
for sql in sqls:
cursor.execute(sql)
connect.commit()
except Exception:
# 出現異常則回滾,並拋出異常
connect.rollback()
raise
finally:
cursor.close()
connect.close()
- 然後在執行下邊的sqls時出現了異常
"""scheme
CREATE table1 (
id: INTEGER PRIMARY KEY
);
CREATE table2 (
id: INTEGER PRIMARY KEY,
foreign_id: INTEGER ,
FOREIGN KEY(foreign_id) REFERENCES table1(id)
);
"""
sqls = [
'INSERT INTO table1(id) VALUES(1);',
'INSERT INTO table2(id, foreign_id) VALUES(1, 1);'
]
update_data(sqls)
# >>> 異常(1452, 'Cannot add or update a child row: a foreign key constraint fails ...')
- 違反外碼約束?也就是說,在事務內,
execute(sql)
後緩存區的新插入數據若未commit
是不能被下一條sql獲取的麼…
解決方法
經過一番瞎試,找到了以下的應對方法,在execute(sql)
後fetch
一下
# 更新數據,可以執行數據的增、刪、改
...
def update_data(self, sqls: list):
connect = self.__get_connect()
cursor = connect.cursor()
try:
for sql in sqls:
cursor.execute(sql)
cursor.fetchone() # 解決方法
connect.commit()
except Exception:
# 出現異常則回滾,並拋出異常
connect.rollback()
raise
finally:
cursor.close()
connect.close()
- 看了官網文檔以及網上的一些
fetch
方法的介紹,由於我python跟mysql也不是很熟悉,還是沒找到fetch
能解決這個問題的原因 - 我自己考慮的是,pymysql事務的緩存機制中,緩存區也有兩個部分,一個部分是準備就緒的數據,這些數據經過了處理,比較符合mysql數據庫規範,即將commit到數據庫中,此時能被事務中的其他操作獲取;另一部分的數據還未準備就緒,仍未進行規範化處理,不能被事務中的其他操作獲取。分區的目的也顯而易見,準備就緒的數據在進行規範化時是比較耗時的。
execute
後的數據默認分配到就緒區,而fetch
函數則能觸發數據規範化操作。 - 大家有什麼看法也歡迎指正哈!灰常感謝!