Python 如何处理数据库事务

news/2024/10/12 18:54:39/

Python 如何处理数据库事务

数据库事务是指一组操作要么全部执行成功,要么全部回滚的过程。事务是确保数据库一致性的重要手段,特别是在处理需要多步操作的场景时,能够避免部分数据成功更新而部分数据失败的情况。本文将详细介绍什么是数据库事务,以及如何在 Python 中通过各种方式(例如,使用 sqlite3MySQLPostgreSQL数据库驱动)处理事务。

在这里插入图片描述

什么是数据库事务?

1. 事务的概念

数据库事务(transaction)是指一组操作,它们被看作是一个单一的逻辑单元,要么全部执行成功,要么全部执行失败。事务具有以下四个特性,简称为 ACID 特性:

  • 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败并回滚。事务不能处于部分成功、部分失败的状态。
  • 一致性(Consistency):事务开始前和结束后,数据库的状态必须保持一致,任何违反数据库规则的操作都不能提交。
  • 隔离性(Isolation):事务之间彼此独立执行,事务的中间状态对于其他事务是不可见的。
  • 持久性(Durability):事务一旦提交,数据将被持久保存,即使发生系统故障也不会丢失。

2. 为什么需要事务?

事务对于保证数据库操作的可靠性和数据的一致性至关重要。以下是几个常见的使用场景:

  • 多步骤的操作:比如,在电商平台中,用户购买商品时,涉及到扣除库存、创建订单和扣减用户账户余额等操作,这些操作必须作为一个整体来执行。如果其中某一个步骤失败,则需要回滚所有已经完成的步骤,确保系统数据不会不一致。
  • 防止部分更新:在同一个操作中,假设有多个更新操作,一旦其中某个操作失败,应该取消其他操作的影响,保证数据库不会处于不完整的更新状态。
  • 并发控制:多个事务同时进行时,事务的隔离性可以避免脏读、不可重复读和幻读等问题。

在 Python 中处理事务

在 Python 中处理数据库事务通常涉及使用数据库驱动(如 sqlite3psycopg2PyMySQL 等),这些驱动通常提供内置的事务管理功能。以下是一些常见数据库库和事务管理的示例。

1. 使用 SQLite 处理事务

SQLite 是一个轻量级的数据库,广泛用于小型应用和开发环境中。在 Python 中,sqlite3 模块提供了事务支持。

事务的基本操作

sqlite3 默认是在“自动提交”模式下运行的,这意味着每个 SQL 语句都是一个事务。但是,你可以手动控制事务的开始和提交。

python">import sqlite3# 连接到数据库
conn = sqlite3.connect('example.db')try:# 创建游标cursor = conn.cursor()# 开始事务(默认自动开始,显示调用 conn.commit() 或 conn.rollback() 来结束)cursor.execute("BEGIN")# 执行多个 SQL 语句cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ("Alice", 30))cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")# 提交事务conn.commit()
except Exception as e:# 出现错误时回滚事务conn.rollback()print(f"Transaction failed: {e}")
finally:# 关闭连接conn.close()

在这个例子中,我们执行了两条 SQL 语句——插入用户数据和更新账户余额。这两条语句被视为一个事务,只有当两者都成功时,才会提交到数据库。一旦其中任何一个操作失败,事务将回滚,取消已完成的操作。

自动提交模式

sqlite3 中,如果不手动控制事务,它将处于自动提交模式。这意味着每条 SQL 语句执行后都会立即提交。

如果你需要在同一个连接中执行多条语句并确保它们作为一个事务执行,则需要手动控制事务,使用 conn.commit()conn.rollback()

2. 使用 MySQL 处理事务

在 MySQL 中,我们可以使用 PyMySQLMySQL Connector/Python 等库来处理事务。

使用 PyMySQL 处理事务
python">import pymysql# 连接到 MySQL 数据库
conn = pymysql.connect(host='localhost',user='root',password='password',db='test_db'
)try:# 创建游标cursor = conn.cursor()# 执行多个 SQL 语句cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Bob", 25))cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 2")# 提交事务conn.commit()
except Exception as e:# 如果有任何错误,回滚事务conn.rollback()print(f"Transaction failed: {e}")
finally:# 关闭连接conn.close()

在 PyMySQL 中,默认情况下事务是手动控制的。在执行完一组操作后,使用 conn.commit() 提交事务;如果发生错误,则使用 conn.rollback() 回滚事务。

使用 MySQL Connector/Python 处理事务

MySQL Connector 是 MySQL 官方提供的 Python 库。事务操作与 PyMySQL 类似。

python">import mysql.connector# 连接到数据库
conn = mysql.connector.connect(host='localhost',user='root',password='password',database='test_db'
)try:cursor = conn.cursor()# 执行多条 SQL 语句cursor.execute("INSERT INTO orders (order_id, user_id) VALUES (%s, %s)", (101, 1))cursor.execute("UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 1")# 提交事务conn.commit()
except Exception as e:# 回滚事务conn.rollback()print(f"Transaction failed: {e}")
finally:conn.close()

在 MySQL 中,事务控制的基本步骤与 PyMySQL 类似,都是先执行 SQL 操作,然后手动提交或回滚事务。

3. 使用 PostgreSQL 处理事务

PostgreSQL 是一个功能强大的开源数据库,支持丰富的事务功能。在 Python 中,psycopg2 是最常用的与 PostgreSQL 交互的库。

使用 psycopg2 处理事务
python">import psycopg2# 连接到 PostgreSQL 数据库
conn = psycopg2.connect(dbname="test_db",user="user",password="password",host="localhost"
)try:cursor = conn.cursor()# 执行 SQL 操作cursor.execute("INSERT INTO employees (name, department) VALUES (%s, %s)", ("John", "HR"))cursor.execute("UPDATE payroll SET salary = salary + 500 WHERE employee_id = 3")# 提交事务conn.commit()
except Exception as e:# 事务失败时回滚conn.rollback()print(f"Transaction failed: {e}")
finally:conn.close()

psycopg2 中的事务处理也是手动控制的,事务的提交和回滚需要明确调用 conn.commit()conn.rollback()

4. Django 中的事务处理

如果你使用的是 Django 这种高级 Web 框架,事务管理会更加简洁。Django 自带事务管理功能,并且有两种主要的事务处理方式:自动管理和手动管理。

自动事务管理

在 Django 中,默认情况下,所有的数据库操作都在自动提交模式下运行。每次数据库操作都会立即提交。

手动事务管理

对于更复杂的事务,Django 提供了 transaction.atomic() 这个上下文管理器,允许你手动控制事务。

python">from django.db import transactiontry:with transaction.atomic():user = User.objects.create(username="alice")Account.objects.create(user=user, balance=1000)
except Exception as e:print(f"Transaction failed: {e}")

在这个示例中,transaction.atomic() 将确保 UserAccount 的创建操作作为一个原子操作。如果任何一个操作失败,整个事务将回滚。

5. SQLAlchemy 中的事务处理

如果你使用 ORM 库如 SQLAlchemy,事务管理也是非常简洁的。SQLAlchemy 允许你在会话(session)级别管理事务。

python">from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import User, Account  # 假设已经定义了 ORM 模型# 连接数据库
engine = create_engine('sqlite:///example.db')
Session = sessionmaker(bind=engine)
session = Session()try:# 创建用户和账户new_user = User(name="Alice")session.add(new_user)new_account = Account(user=new_user, balance=1000)session.add(new_account)# 提交事务session.commit()
except Exception as e:# 事务回滚session.rollback()print(f"Transaction failed: {e}")
finally:session.close()

SQLAlchemy 提供了与数据库会话绑定的事务管理,确保所有操作作为一个事务执行。

事务处理中的常见问题

1. 并发事务问题

在多用户同时操作数据库时,可能会出现并发事务的问题。常见的并发问题有:

  • 脏读(Dirty Read):一个事务读取到另一个事务未提交的数据。
  • 不可重复读(Non-repeatable Read):在一个事务中,两次读取同一数据,得到的结果不同。
  • 幻读(Phantom Read):在一个事务中,读取相同条件的数据两次,得到的行数不同。

为了解决这些问题,数据库提供了不同的隔离级别,如:

  1. Read Uncommitted:允许脏读。
  2. Read Committed:只允许读取已提交的事务数据。
  3. Repeatable Read:防止不可重复读。
  4. Serializable:防止幻读,保证事务串行执行。

不同数据库对隔离级别的实现有所不同,开发者应根据具体应用场景选择合适的隔离级别。

2. 死锁问题

死锁是指两个或多个事务互相等待对方持有的资源,导致系统无法继续执行。为了解决死锁问题,数据库通常会有自动检测和解除死锁的机制,开发者也可以通过减少锁的持有时间和访问顺序来避免死锁。

总结

事务是确保数据库一致性和可靠性的关键机制。在 Python 中,无论是使用原生的数据库驱动,还是使用 ORM 工具如 Django 和 SQLAlchemy,都可以方便地管理数据库事务。开发者需要根据实际需求,选择合适的事务管理方式,避免常见的并发问题和死锁问题。


http://www.ppmy.cn/news/1537979.html

相关文章

【秋招笔试】10.12小米(已改编)秋招-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 本次的三题全部上线…

【LeetCode HOT 100】详细题解之回溯篇

【LeetCode HOT 100】详细题解之回溯篇 回溯法的理论基础回溯法解决的问题理解回溯法回溯法模板 46 全排列思路代码 78 子集思路代码 17 电话号码的字母组合思路代码 39 组合总和思路代码 22 括号生成思路代码 79 单词搜索思路代码 131 分割回文串思路代码 51 N皇后思路代码 回…

封装代码片段语法 vue2语法

关于函数导入 1.在untils写一个pdfService.js 关于pdf预览和下载的方法 export const previewPdf async (record) > {const pdfUrln record.url; // 直接使用 PDF 文件的 URL// const pdfUrln indexConfig.VITE_GLOB_VIEW_URL static/pdf/web/viewer.html?file reco…

桂林自闭症寄宿学校:用关爱点亮未来

在繁华的广州,隐藏着一片宁静而充满爱的天地——星贝育园自闭症儿童寄宿制学校。这里,不仅是一所学府,更是一个心灵的港湾,为自闭症儿童提供了一个安全、包容、充满希望的成长环境。自闭症,这个看似遥远却与我们息息相…

Github 2024-10-09 C开源项目日报 Top9

根据Github Trendings的统计,今日(2024-10-09统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目9PLpgSQL项目1开源时间序列SQL数据库:PostgreSQL扩展 创建周期:2503 天开发语言:C协议类型:OtherStar数量:15982 个Fork数量:838 次关…

ansible 剧本模式

目录 1.剧本格式 ​编辑​编辑2.案例1创建目录分发文件剧本 2.1剧本中用到的命令 2.2书写具体剧本 3.案例2 分发 安装软件包 启动服务的剧本 3.1下载软件包 3.2用yum安装 3.3启动服务 4.找出ansible中对应的模块 5.剧本实现 4.ansible 剧本变量 4.1常用的…

Oracle EBS中 薪资管理 模块的财务流程概览

Oracle E-Business Suite (EBS) 中的薪资管理模块(Oracle Payroll)是企业资源规划(ERP)系统中一个关键部分,它负责处理员工的薪酬计算、支付以及相关的财务事务,帮助企业快速调整员工薪资并提高薪资管理效率。以下是薪资管理模块的…

【Java】 —— 数据结构与集合源码:Vector、LinkedList在JDK8中的源码剖析

目录 7.2.4 Vector部分源码分析 7.3 链表LinkedList 7.3.1 链表与动态数组的区别 7.3.2 LinkedList源码分析 启示与开发建议 7.2.4 Vector部分源码分析 jdk1.8.0_271中: //属性 protected Object[] elementData; protected int elementCount;//构造器 public …