Python使用MySQL事務(wù)的三種主流方式
在實際開發(fā)中,單條 SQL 往往不夠用。轉(zhuǎn)賬、訂單處理、庫存扣減……這些場景要求多條 SQL 要么全成功,要么全失敗。這就是事務(wù)存在的意義。
本文用 Python 實戰(zhàn)講解如何正確使用 MySQL 事務(wù),覆蓋 pymysql、mysql-connector-python 和 SQLAlchemy 三種主流方式。
一、先搞懂事務(wù)的核心:ACID
| 特性 | 含義 | 舉例 |
|---|---|---|
| Atomicity(原子性) | 操作不可分割,全做或全不做 | 轉(zhuǎn)賬:扣款和入賬必須同時成功 |
| Consistency(一致性) | 事務(wù)前后數(shù)據(jù)保持一致 | 余額不能憑空消失 |
| Isolation(隔離性) | 并發(fā)事務(wù)互不干擾 | 兩人同時取錢,不能互相影響 |
| Durability(持久性) | 提交后數(shù)據(jù)永久保存 | 服務(wù)器重啟數(shù)據(jù)不丟失 |
一句話:事務(wù)就是保證數(shù)據(jù)不出亂子的機制。
二、方式一:pymysql(最常用)
2.1 基本用法
import pymysql
conn = pymysql.connect(
host='localhost',
user='root',
password='your_password',
database='test_db',
charset='utf8mb4'
)
try:
with conn.cursor() as cursor:
# 開啟事務(wù)(默認(rèn)就是手動提交模式)
sql1 = "UPDATE accounts SET balance = balance - 100 WHERE user_id = 1"
sql2 = "UPDATE accounts SET balance = balance + 100 WHERE user_id = 2"
cursor.execute(sql1)
cursor.execute(sql2)
# 全部成功,提交
conn.commit()
print("轉(zhuǎn)賬成功")
except Exception as e:
# 任何一步出錯,回滾
conn.rollback()
print(f"轉(zhuǎn)賬失敗,已回滾:{e}")
finally:
conn.close()
2.2 關(guān)鍵點
conn.commit()提交事務(wù)conn.rollback()回滾事務(wù)- 出錯必須回滾,否則已執(zhí)行的 SQL 不會撤銷
- 默認(rèn)
autocommit=False,所以需要手動提交
三、方式二:mysql-connector-python(官方驅(qū)動)
import mysql.connector
conn = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='test_db'
)
cursor = conn.cursor()
try:
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")
conn.commit()
except mysql.connector.Error as err:
conn.rollback()
print(f"Error: {err}")
finally:
cursor.close()
conn.close()
和 pymysql 邏輯一致,只是 API 略有不同。
四、方式三:SQLAlchemy ORM(推薦大型項目)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
Base = declarative_base()
class Account(Base):
__tablename__ = 'accounts'
id = Column(Integer, primary_key=True)
name = Column(String(50))
balance = Column(Integer)
engine = create_engine('mysql+pymysql://root:password@localhost/test_db')
Session = sessionmaker(bind=engine)
session = Session()
try:
account1 = session.query(Account).filter_by(id=1).with_for_update().first()
account2 = session.query(Account).filter_by(id=2).with_for_update().first()
account1.balance -= 100
account2.balance += 100
session.commit()
print("轉(zhuǎn)賬成功")
except Exception as e:
session.rollback()
print(f"轉(zhuǎn)賬失?。簕e}")
finally:
session.close()
為什么用with_for_update()?
普通查詢在并發(fā)下可能讀到臟數(shù)據(jù)。with_for_update() 會加行鎖,確保這條記錄在事務(wù)結(jié)束前不被其他事務(wù)修改,解決并發(fā)問題。
五、三種方式對比
| 維度 | pymysql | mysql-connector | SQLAlchemy |
|---|---|---|---|
| 上手難度 | ?? | ?? | ??? |
| 性能 | 快 | 快 | 稍慢(有 ORM 開銷) |
| 適用場景 | 輕量腳本、小項目 | 官方驅(qū)動、穩(wěn)定需求 | 中大型項目 |
| 并發(fā)控制 | 手動寫 SQL | 手動寫 SQL | with_for_update() 內(nèi)置 |
選型建議:小項目用 pymysql,追求穩(wěn)定用官方驅(qū)動,項目大了直接上 SQLAlchemy。
六、常見坑 & 最佳實踐
坑1:異常沒捕獲,事務(wù)沒回滾
# ? 錯誤示范 cursor.execute(sql1) cursor.execute(sql2) # 如果這里報錯,sql1 已執(zhí)行但沒回滾 conn.commit()
必須用 try/except 包裹,except 里調(diào)用 rollback()。
坑2:連接池里的事務(wù)混亂
用連接池時,確保一個連接只處理一個事務(wù),不要跨連接做事務(wù)操作。
坑3:忘了設(shè)置隔離級別
MySQL 默認(rèn)隔離級別是 REPEATABLE READ,但有些場景需要 READ COMMITTED:
conn.begin() # 顯式開啟事務(wù)
cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
最佳實踐清單
- ? 事務(wù)里的 SQL 盡量少,減少鎖持有時間
- ? 捕獲所有異常,確?;貪L
- ? 高并發(fā)場景加行鎖(
SELECT ... FOR UPDATE) - ? 生產(chǎn)環(huán)境用連接池(如
DBUtils、SQLAlchemy內(nèi)置池) - ? 不要在事務(wù)里做網(wǎng)絡(luò)請求、文件 IO 等耗時操作
七、總結(jié)
| 你的場景 | 推薦方案 |
|---|---|
| 寫個腳本批量處理數(shù)據(jù) | pymysql + 手動 commit/rollback |
| 官方項目,求穩(wěn)定 | mysql-connector-python |
| Web 項目、多人協(xié)作 | SQLAlchemy + with_for_update() |
事務(wù)不復(fù)雜,但用錯了比不用更危險。記住三個動作:begin → commit / rollback → close,就能覆蓋 90% 的場景。
以上就是Python使用MySQL事務(wù)的三種主流方式的詳細內(nèi)容,更多關(guān)于Python使用MySQL事務(wù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python基礎(chǔ)知識學(xué)習(xí)之類的繼承
今天帶大家學(xué)習(xí)Python的基礎(chǔ)知識,文中對python類的繼承作了非常詳細的介紹,對正在學(xué)習(xí)python基礎(chǔ)的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05
Pycharm shell配置帶你解決Pycharm終端進不了conda虛擬環(huán)境的情況
這篇文章主要介紹了Pycharm shell配置帶你解決Pycharm終端進不了conda虛擬環(huán)境的情況,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2026-05-05
詳解從Django Rest Framework響應(yīng)中刪除空字段
這篇文章主要介紹了詳解從Django Rest Framework響應(yīng)中刪除空字段,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01

