Python操作数据库需通过驱动建立连接并执行SQL,遵循连接、创建游标、执行SQL、提交事务、关闭连接的流程,使用参数化查询防SQL注入,结合try-except-finally管理事务确保数据一致性。

Python操作数据库的核心在于通过特定的数据库驱动(如
sqlite3
psycopg2
mysql-connector-python
要使用Python操作数据库,我们通常会遵循一套相对标准的流程,这套流程基于Python的DB-API 2.0规范,虽然具体实现会因数据库类型和所选驱动而异,但核心逻辑是相通的。这里以Python内置的
sqlite3
首先,你需要一个数据库文件。如果文件不存在,
sqlite3
import sqlite3
# 1. 连接数据库
# 如果数据库文件不存在,会自动创建
try:
conn = sqlite3.connect('my_database.db')
print("数据库连接成功。")
# 2. 创建游标对象
# 游标用于执行SQL命令
cursor = conn.cursor()
# 3. 创建表(如果不存在)- Create Schema
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
age INTEGER
)
''')
conn.commit() # 提交事务,保存表结构更改
print("表 'users' 创建或已存在。")
# --- CRUD 操作示例 ---
# C - Create (插入数据)
# 使用参数化查询防止SQL注入
user_data = [
('Alice', 'alice@example.com', 30),
('Bob', 'bob@example.com', 24),
('Charlie', 'charlie@example.com', 35)
]
for name, email, age in user_data:
try:
cursor.execute("INSERT INTO users (name, email, age) VALUES (?, ?, ?)", (name, email, age))
print(f"插入用户: {name}")
except sqlite3.IntegrityError:
print(f"用户 {name} ({email}) 已存在,跳过插入。")
conn.commit() # 提交事务,保存数据更改
# R - Read (查询数据)
print("\n--- 查询所有用户 ---")
cursor.execute("SELECT id, name, email, age FROM users")
users = cursor.fetchall() # 获取所有结果
for user in users:
print(f"ID: {user[0]}, 姓名: {user[1]}, 邮箱: {user[2]}, 年龄: {user[3]}")
print("\n--- 查询特定用户(年龄大于25)---")
cursor.execute("SELECT name, email FROM users WHERE age > ?", (25,))
older_users = cursor.fetchall()
for user in older_users:
print(f"姓名: {user[0]}, 邮箱: {user[1]}")
# U - Update (更新数据)
print("\n--- 更新用户数据 ---")
new_email = 'alice_new@example.com'
old_email = 'alice@example.com'
cursor.execute("UPDATE users SET email = ? WHERE email = ?", (new_email, old_email))
if cursor.rowcount > 0:
print(f"用户 {old_email} 的邮箱已更新为 {new_email}。")
else:
print(f"未找到邮箱为 {old_email} 的用户进行更新。")
conn.commit() # 提交事务
# 再次查询确认更新
print("\n--- 确认更新后的用户数据 ---")
cursor.execute("SELECT name, email FROM users WHERE email = ?", (new_email,))
updated_alice = cursor.fetchone()
if updated_alice:
print(f"更新后的Alice: 姓名: {updated_alice[0]}, 邮箱: {updated_alice[1]}")
# D - Delete (删除数据)
print("\n--- 删除用户数据 ---")
user_to_delete = 'Bob'
cursor.execute("DELETE FROM users WHERE name = ?", (user_to_delete,))
if cursor.rowcount > 0:
print(f"用户 {user_to_delete} 已被删除。")
else:
print(f"未找到用户 {user_to_delete} 进行删除。")
conn.commit() # 提交事务
# 再次查询确认删除
print("\n--- 确认删除后的所有用户 ---")
cursor.execute("SELECT name FROM users")
remaining_users = cursor.fetchall()
if remaining_users:
print("当前剩余用户:", [user[0] for user in remaining_users])
else:
print("数据库中已无用户。")
except sqlite3.Error as e:
print(f"数据库操作发生错误: {e}")
finally:
# 4. 关闭连接
if conn:
conn.close()
print("\n数据库连接已关闭。")
这段代码展示了一个完整的CRUD流程。需要注意的是,每次对数据库进行修改(INSERT, UPDATE, DELETE)后,都需要调用
conn.commit()
conn.rollback()
立即学习“Python免费学习笔记(深入)”;
在Python的世界里,连接各种数据库的库非常丰富,这得益于Python DB-API 2.0规范的存在,它为数据库驱动提供了一套统一的接口。这使得我们在切换不同数据库时,核心的CRUD逻辑可以保持相对一致。
常用数据库连接库(驱动):
sqlite3
psycopg2
asyncpg
mysql-connector-python
PyMySQL
pyodbc
mssql-tools
cx_Oracle
python-oracledb
如何选择合适的数据库驱动?
选择合适的数据库驱动,不仅仅是看它能连上数据库,更要考虑项目的实际需求和未来的发展。
psycopg2
mysql-connector-python
PyMySQL
asyncpg
我个人在选择时,倾向于优先选择官方或社区广泛推荐的驱动,因为它们通常更稳定、功能更全面、社区支持更好。如果项目对性能有极致要求,我才会深入研究异步驱动或更底层的实现。
SQL注入是数据库安全领域一个老生常谈但又极其重要的议题。它发生在应用程序将用户输入直接拼接进SQL查询字符串,导致恶意用户可以通过输入特定的SQL片段来改变查询的意图,从而窃取、篡改数据甚至完全控制数据库。防止SQL注入,在Python中,核心且最有效的方法是使用参数化查询(Parameterized Queries),也称为预处理语句(Prepared Statements)。
参数化查询的原理:
参数化查询的原理是SQL代码和查询参数是分开传递给数据库的。数据库会先解析SQL语句的结构,确定要执行的操作,然后将参数值绑定到相应的位置。这样,即使参数中包含恶意的SQL片段,数据库也只会将其视为普通的数据值,而不是可执行的SQL代码。
Python中的实现:
几乎所有的Python数据库驱动都支持参数化查询。它们通常使用占位符(placeholder)来表示参数。占位符的样式会因驱动而异:
sqlite3
psycopg2
?
import sqlite3
conn = sqlite3.connect('my_database.db')
cursor = conn.cursor()
user_input_name = "Robert'); DROP TABLE users;--" # 恶意输入
user_input_email = "robert@example.com"
# 错误示例:直接拼接字符串,易受SQL注入攻击
# cursor.execute(f"INSERT INTO users (name, email) VALUES ('{user_input_name}', '{user_input_email}')")
# 正确示例:使用参数化查询
cursor.execute("INSERT INTO users (name, email) VALUES (?, ?)", (user_input_name, user_input_email))
conn.commit()
print("使用参数化查询,恶意输入被当作普通数据处理。")
conn.close()在这个例子中,即使
user_input_name
DROP TABLE users
mysql-connector-python
PyMySQL
%s
%(name)s
# 假设你已经连接了MySQL数据库
# import mysql.connector
# conn = mysql.connector.connect(...)
# cursor = conn.cursor()
# user_input_name = "Robert'); DROP TABLE users;--"
# user_input_email = "robert@example.com"
# 使用位置占位符
# cursor.execute("INSERT INTO users (name, email) VALUES (%s, %s)", (user_input_name, user_input_email))
# 使用命名占位符(更具可读性)
# cursor.execute("INSERT INTO users (name, email) VALUES (%(name)s, %(email)s)",
# {'name': user_input_name, 'email': user_input_email})
# conn.commit()注意事项:
INSERT
SELECT
UPDATE
DELETE
LIKE
LIKE
%
_
search_term = "%Alice%" # 通配符是参数值的一部分
cursor.execute("SELECT name FROM users WHERE name LIKE ?", (search_term,))通过始终坚持使用参数化查询,可以极大地提高应用程序的数据库安全性,有效抵御SQL注入攻击。
事务(Transaction)是数据库管理系统(DBMS)执行过程中的一个逻辑工作单元,它包含一系列操作,这些操作要么全部成功提交,要么全部失败回滚。事务的核心目的是确保数据的一致性(Consistency)、原子性(Atomicity)、隔离性(Isolation)和持久性(Durability),通常称为ACID特性。在Python中操作数据库时,正确管理事务对于维护数据的完整性和可靠性至关重要。
Python中的事务管理:
大多数Python数据库驱动都遵循DB-API 2.0规范,提供了明确的事务管理机制:
conn.commit()
INSERT
UPDATE
DELETE
conn.commit()
conn.rollback()
conn.rollback()
默认行为:
INSERT
UPDATE
DELETE
BEGIN TRANSACTION
sqlite3
execute()
conn.commit()
conn.commit()
事务管理的典型场景和实践:
假设我们有一个转账操作,需要从一个账户扣钱,同时给另一个账户加钱。这两个操作必须作为一个整体成功或失败。
import sqlite3
conn = sqlite3.connect('bank.db')
cursor = conn.cursor()
# 创建账户表
cursor.execute('''
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
balance REAL NOT NULL DEFAULT 0.0
)
''')
conn.commit()
# 初始化账户(如果不存在)
def ensure_account(name, initial_balance):
cursor.execute("SELECT id FROM accounts WHERE name = ?", (name,))
if not cursor.fetchone():
cursor.execute("INSERT INTO accounts (name, balance) VALUES (?, ?)", (name, initial_balance))
conn.commit()
print(f"创建账户: {name}, 余额: {initial_balance}")
ensure_account('Alice', 1000.0)
ensure_account('Bob', 500.0)
def transfer_money(sender_name, receiver_name, amount):
if amount <= 0:
print("转账金额必须大于零。")
return False
try:
# 开始事务
# 在sqlite3中,只要不调用commit,所有的修改都会累积在一个事务中
# 显式地,你也可以用 BEGIN TRANSACTION
# 1. 检查发送方余额
cursor.execute("SELECT balance FROM accounts WHERE name = ?", (sender_name,))
sender_balance = cursor.fetchone()[0]
if sender_balance < amount:
print(f"账户 {sender_name} 余额不足。")
conn.rollback() # 余额不足,回滚事务
return False
# 2. 从发送方账户扣款
cursor.execute("UPDATE accounts SET balance = balance - ? WHERE name = ?", (amount, sender_name))
# 模拟一个可能发生的错误,例如网络中断、数据库死锁等
# if sender_name == 'Alice' and amount == 200:
# raise ValueError("模拟转账失败!")
# 3. 给接收方账户加款
cursor.execute("UPDATE accounts SET balance = balance + ? WHERE name = ?", (amount, receiver_name))
# 所有操作成功,提交事务
conn.commit()
print(f"成功从 {sender_name} 转账 {amount} 到 {receiver_name}。")
return True
except Exception as e:
print(f"转账过程中发生错误: {e}")
conn.rollback() # 发生任何错误,回滚事务
return False
# 尝试转账
print("\n--- 首次转账 ---")
transfer_money('Alice', 'Bob', 100.0)
# 查看账户余额
print("\n--- 账户余额 ---")
cursor.execute("SELECT name, balance FROM accounts")
for account in cursor.fetchall():
print(f"账户: {account[0]}, 余额: {account[1]}")
# 尝试一个会失败的转账(余额不足)
print("\n--- 尝试失败转账(余额不足) ---")
transfer_money('Bob', 'Alice', 1000.0)
# 再次查看账户余额,确认未发生更改
print("\n--- 账户余额(失败转账后) ---")
cursor.execute("SELECT name, balance FROM accounts")
for account in cursor.fetchall():
print(f"账户: {account[0]}, 余额: {account[1]}")
conn.close()关键点:
try...except...finally
try
try
conn.commit()
try
except
conn.rollback()
finally
上下文管理器(with
with
with
# 示例:使用with语句管理连接(如果conn对象支持)
# 在sqlite3中,连接对象本身不支持with,但我们可以通过自定义上下文管理器或使用ORM来实现
# 对于sqlite3,更常见的模式是:
# with sqlite3.connect('my_database.db') as conn:
# cursor = conn.cursor()
# # ... 执行操作 ...
# # conn.commit() 在with块结束时会自动提交,如果没发生以上就是Python怎样操作数据库_Python数据库CRUD步骤解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号