Python操作Mysql数据库
一,简介
Python 连接 MySQL 数据库是通过 MySQL 驱动程序实现的,常见的驱动有mysql-connector-python
和PyMySQL
。以mysql-connector-python
为例,它是 MySQL 官方提供的驱动,能让 Python 程序与 MySQL 数据库进行交互,实现数据的增删改查等操作。
优点
- 开源免费:MySQL 是开源数据库,Python 也是开源语言,使用成本低。
- 跨平台兼容:Python 和 MySQL 都支持多种操作系统,方便开发和部署。
- 高性能:MySQL 处理大量数据时性能优越,适合企业级应用。
- 丰富的驱动支持:有多个成熟的驱动可供选择,满足不同场景需求。
- 广泛的社区支持:遇到问题容易找到解决方案。
缺点
- 事务支持有限:虽然 InnoDB 存储引擎支持事务,但相比专业数据库如 Oracle,功能较弱。
- 复杂查询性能下降:对于复杂的关联查询,性能可能不如专业数据库。
- 安全机制较简单:MySQL 的安全机制相对简单,需要开发者自己加强安全措施。
- 驱动兼容性问题:不同版本的 MySQL 和驱动可能存在兼容性问题,需要注意版本匹配。
二,安装
1. 安装 MySQL 驱动程序
Python 连接 MySQL 8 最常用的驱动有两种,选择其一即可:
方法一:使用官方驱动 mysql-connector-python
这是 MySQL 官方提供的纯 Python 驱动,无需额外安装 C 库,兼容性好。
pip3 install mysql-connector-python
方法二:使用 PyMySQL
这是另一个流行的纯 Python 驱动,语法与 MySQLdb 兼容。
pip3 install pymysql
2. 可能需要的额外依赖
加密支持(可选)
如果 MySQL 服务器启用了强密码加密(如caching_sha2_password
,MySQL 8 默认),可能需要安装:
pip3 install cryptography
- 说明:
mysql-connector-python
和PyMySQL
通常会自动处理加密,但复杂场景下可能需要cryptography
库。
总结
- 必装:
mysql-connector-python
或PyMySQL
。 - 可选:
cryptography
(处理复杂加密场景)。
三,示例
我的库名testdb 里面两个表 users orders
python连接mysql并查看users表内的内容
import pymysql
# 建立数据库连接
db = pymysql.connect(
host='192.168.10.101', # 数据库服务器地址
user='root', # 数据库用户名
password='pwd123', # 数据库密码
database='testdb' # 要连接的数据库名
)
# 创建游标对象,用于执行SQL语句
cursor = db.cursor()
try:
# 执行SQL查询语句,查询users表中的所有记录
cursor.execute('SELECT * FROM users')
# 获取查询结果集
results = cursor.fetchall()
# 遍历结果集并打印每一行数据
for row in results:
print(row)
except Exception as e:
print(f"查询过程中发生错误: {e}")
finally:
# 关闭游标,释放资源
cursor.close()
# 关闭数据库连接
db.close()
代码说明:
- 数据库连接:通过
pymysql.connect()
方法创建数据库连接对象,需要提供主机地址、用户名、密码和数据库名。 - 游标操作:使用
db.cursor()
创建游标对象,该对象用于执行 SQL 语句并处理结果。 - SQL 执行:调用
cursor.execute()
方法执行 SQL 查询语句,这里查询的是users
表的所有记录。 - 结果处理:使用
cursor.fetchall()
获取查询结果集,返回一个元组列表,每个元组代表一条记录。 - 资源释放:无论查询是否成功,最终都需要关闭游标和数据库连接,避免资源泄漏。
验证:
[root@localhost ~]# python3 a.py
(1, 'Alice', 25)
(2, 'Bob', 30)
(3, 'Charlie', 35)
(4, 'David', 28)
!!!#成功
插入内容
import pymysql
# 建立数据库连接
db = pymysql.connect(
host='192.168.10.101', # 数据库服务器地址
user='root', # 数据库用户名
password='pwd123', # 数据库密码
database='testdb' # 要连接的数据库名
)
# 创建游标对象,用于执行SQL语句
cursor = db.cursor()
try:
# 执行插入语句,使用参数化查询防止SQL注入
# %s是pymysql的占位符,对应后面元组中的值
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('zhangsan', 99))
# 提交事务,将插入操作持久化到数据库
db.commit()
# 执行查询语句,查看插入后的结果
cursor.execute('SELECT * FROM users')
# 获取查询结果集
results = cursor.fetchall()
# 遍历结果集并打印每一行数据
for row in results:
print(row)
except Exception as e:
# 发生异常时回滚事务
db.rollback()
print(f"操作过程中发生错误: {e}")
finally:
# 关闭游标,释放资源
cursor.close()
# 关闭数据库连接
db.close()
代码说明:
- 数据库连接:与之前相同,创建数据库连接对象。
- 插入操作
- 使用
cursor.execute()
执行插入语句,通过参数化查询方式传递值 - 参数化查询可有效防止 SQL 注入攻击
- 使用
- 事务提交
- 插入操作属于写操作,需要通过
db.commit()
提交事务 - 如果不提交,数据不会真正写入数据库
- 插入操作属于写操作,需要通过
- 查询验证
- 插入后执行查询语句,验证数据是否成功插入
- 结果集处理方式与之前相同
- 异常处理
- 添加了
db.rollback()
在发生异常时回滚事务 - 确保数据一致性
- 添加了
验证:
[root@localhost ~]# python3 a.py
(1, 'Alice', 25)
(2, 'Bob', 30)
(3, 'Charlie', 35)
(4, 'David', 28)
(5, 'zhangsan', 99)
创建连接池
使用说明:
- 安装依赖:
pip3 install DBUtils pymysql
- 连接池特点:
- 自动管理连接的创建和回收
- 支持最小 / 最大连接数配置
- 支持连接耗尽时的阻塞策略
- 使用上下文管理器确保连接自动关闭
- 核心方法:
get_connection()
:获取数据库连接execute(sql, params)
:执行 SQL 语句,自动处理查询结果和事务
- 安全考虑:
- 所有 SQL 操作都使用参数化查询
- 自动处理事务回滚
- 支持字典格式的结果集
- 性能优化:
- 默认返回字典格式结果,便于处理
- 连接可复用,减少开销
- 支持连接池参数调优
代码
from dbutils.pooled_db import PooledDB
import pymysql
class MySQLPool:
"""MySQL数据库连接池类"""
def __init__(self, host, user, password, database,
mincached=1, maxcached=10,
maxconnections=20, blocking=True):
"""
初始化数据库连接池
Args:
host: 数据库主机地址
user: 数据库用户名
password: 数据库密码
database: 数据库名
mincached: 连接池中空闲连接的初始数量
maxcached: 连接池中空闲连接的最大数量
maxconnections: 允许的最大连接数
blocking: 连接池达到最大连接数时是否阻塞
"""
self.pool = PooledDB(
creator=pymysql, # 使用pymysql作为数据库驱动
host=host,
user=user,
password=password,
database=database,
charset='utf8mb4', # 支持中文和特殊字符
cursorclass=pymysql.cursors.DictCursor, # 返回字典格式的结果
mincached=mincached,
maxcached=maxcached,
maxconnections=maxconnections,
blocking=blocking
)
def get_connection(self):
"""从连接池获取一个连接"""
return self.pool.connection()
def execute(self, sql, params=None, commit=True):
"""执行SQL语句
Args:
sql: SQL语句
params: SQL参数
commit: 是否提交事务
Returns:
对于查询语句,返回结果列表;对于修改语句,返回受影响的行数
"""
with self.get_connection() as conn:
with conn.cursor() as cursor:
try:
cursor.execute(sql, params or ())
if sql.strip().lower().startswith('select'):
return cursor.fetchall()
else:
if commit:
conn.commit()
return cursor.rowcount
except Exception as e:
if commit:
conn.rollback()
raise e
# 使用示例
if __name__ == "__main__":
# 创建连接池实例
db_pool = MySQLPool(
host='192.168.10.101',
user='root',
password='pwd123',
database='testdb'
)
# 执行查询
users = db_pool.execute("SELECT * FROM users WHERE age > %s", (25,))
for user in users:
print(user)
# 执行插入
result = db_pool.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("test", 30))
print(f"插入成功,受影响行数: {result}")
四,%s的含义
1. 为什么需要参数化查询?
直接拼接字符串会导致 SQL 注入风险。
例如:
# 危险!不要这样做!
name = "zhangsan'; DROP TABLE users; --"
query = f"SELECT * FROM users WHERE name = '{name}'"
cursor.execute(query)
恶意输入可能会破坏数据库。
2. %s
的作用
%s
告诉数据库驱动:“这里有一个动态值,需要安全地插入到 SQL 语句中”。驱动会自动处理转义和类型转换。
安全示例:
name = "zhangsan"
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
- 占位符:
%s
是值的占位符,无论值是什么类型。 - 参数分离:实际值通过元组
(name,)
传递给execute()
,与 SQL 语句分离。
3. 如何使用 %s
?
单值查询
age = 25
cursor.execute("SELECT * FROM users WHERE age > %s", (age,))
多值插入
data = ("zhangsan", 25)
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", data)
批量插入
users = [("lisi", 30), ("wangwu", 35)]
cursor.executemany("INSERT INTO users (name, age) VALUES (%s, %s)", users)
4. 注意事项
- 仅用于值:
%s
只能替换值(如WHERE name = %s
),不能用于表名、列名等 SQL 关键字。 - 与 Python 字符串格式化的区别:
- Python 字符串格式化:
"Hello %s" % name
- SQL 参数化查询:
"SELECT * FROM users WHERE name = %s"
(语法相似,但用途不同)
- Python 字符串格式化:
- 不同数据库驱动的占位符:
- PyMySQL/mysql-connector:使用
%s
。 - SQLite3:使用
?
(例如:WHERE name = ?
)。 - PostgreSQL (psycopg2):也使用
%s
。
- PyMySQL/mysql-connector:使用
5. 为什么 %s
更安全?
- 自动转义:驱动会自动处理特殊字符(如引号),防止 SQL 注入。
- 类型安全:无需手动处理引号(字符串会自动加引号,数字不会)。
- 性能优化:预编译 SQL 语句,减少数据库解析开销。
五,事务管理
在 Python 中连接 MySQL 数据库时,事务管理是确保数据一致性和完整性的关键机制。下面我将详细解释如何管理事务,并提供示例代码。
一、事务的四大特性(ACID)
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败回滚。
- 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务。
- 持久性(Durability):事务一旦提交,其结果应该永久保存在数据库中。
二、Python 中管理 MySQL 事务的方法
1. 手动管理事务(基础方法)
使用 PyMySQL 连接时,默认自动提交(autocommit=True
),需要手动关闭自动提交来管理事务:
import pymysql
# 建立数据库连接
conn = pymysql.connect(
host='localhost',
user='root',
password='password',
database='testdb'
)
try:
# 关闭自动提交,开启事务
conn.autocommit(False)
cursor = conn.cursor()
# 执行多个SQL操作
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Alice", 25))
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
# 提交事务
conn.commit()
print("事务提交成功")
except Exception as e:
# 发生异常时回滚事务
conn.rollback()
print(f"事务回滚: {e}")
finally:
# 恢复自动提交模式并关闭连接
conn.autocommit(True)
conn.close()
2. 使用上下文管理器(推荐方法)
通过自定义上下文管理器,可以更优雅地管理事务:
import pymysql
from contextlib import contextmanager
# 创建数据库连接
def get_db_connection():
return pymysql.connect(
host='localhost',
user='root',
password='password',
database='testdb'
)
# 定义事务上下文管理器
@contextmanager
def transaction():
conn = get_db_connection()
conn.autocommit(False)
try:
yield conn # 返回连接供外部使用
conn.commit() # 提交事务
except Exception as e:
conn.rollback() # 回滚事务
raise e
finally:
conn.autocommit(True)
conn.close()
# 使用事务上下文管理器
with transaction() as conn:
with conn.cursor() as cursor:
cursor.execute("INSERT INTO users (name, age) VALUES (%s, %s)", ("Bob", 30))
cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")
3. 使用连接池管理事务(生产环境推荐)
使用DBUtils
库创建连接池,并结合上下文管理器管理事务:
from dbutils.pooled_db import PooledDB
import pymysql
from contextlib import contextmanager
# 创建连接池
pool = PooledDB(
creator=pymysql,
host='localhost',
user='root',
password='password',
database='testdb',
mincached=2,
maxcached=5
)
# 事务上下文管理器
@contextmanager
def transaction():
conn = pool.connection()
conn.autocommit(False)
try:
yield conn
conn.commit()
except Exception as e:
conn.rollback()
raise e
finally:
conn.autocommit(True)
conn.close()
# 在事务中执行多个操作
with transaction() as conn:
with conn.cursor() as cursor:
# 转账操作:从账户1转100到账户2
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")
三、事务隔离级别
MySQL 支持四种隔离级别,通过SET SESSION TRANSACTION ISOLATION LEVEL
语句设置:
- READ UNCOMMITTED(读未提交):最低级别,可能读取到未提交的数据(脏读)。
- READ COMMITTED(读已提交):避免脏读,但可能出现不可重复读。
- REPEATABLE READ(可重复读):MySQL 默认级别,确保同一事务中多次读取结果一致。
- SERIALIZABLE(串行化):最高级别,强制事务串行执行,避免所有并发问题。
设置隔离级别示例:
with conn.cursor() as cursor:
cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
# 执行事务操作
四、关键要点总结
- 事务边界:明确事务的开始(关闭自动提交)和结束(提交或回滚)。
- 异常处理:必须捕获异常并回滚,确保事务的原子性。
- 资源管理:使用上下文管理器自动关闭连接和游标。
- 隔离级别:根据业务需求选择合适的隔离级别,避免脏读、幻读等问题。
- 连接池:生产环境中使用连接池提高性能,减少连接开销。
合理使用事务可以确保数据的一致性和完整性,特别是在涉及转账、库存管理等关键业务场景中尤为重要。