bash
def get_db():
"""建立并返回 MySQL 数据库连接(从环境变量获取配置,默认返回 DictCursor 游标)"""
return pymysql.connect(
host=get_env('PYTHON_DB_HOST', 'ip'),
port=int(get_env('PYTHON_DB_PORT', '端口')),
user=get_env('PYTHON_DB_USERNAME', '用户名'),
password=get_env('PYTHON_DB_PASSWORD', '密码'),
database=get_env('PYTHON_DB_DATABASE', '数据库名'),
cursorclass=pymysql.cursors.DictCursor, # 查询结果自动封装为 Python 字典
autocommit=True # 开启自动提交
)
作用:从环境变量动态读取数据库配置(包含兜底默认值),建立并返回一个配置好的 PyMySQL 连接对象。
分布拆解方法:
return pymysql.connect()
pymysql.connect() 是 Python 中 PyMySQL 驱动连接 MySQL 数据库的核心方法。它接收一系列配置参数,建立并返回一个数据库连接对象(Connection)。
通常包含以下参数:
bash
import pymysql
db_connection = pymysql.connect(
host='127.0.0.1', # 数据库服务器地址 (可以是 IP 或域名)
port=3306, # 数据库端口 (整数类型,默认为 3306)
user='root', # 数据库登录用户名
password='your_password', # 数据库登录密码
database='my_db', # 要连接的数据库名称 (也可以写作 db='my_db')
charset='utf8mb4', # 字符集编码 (强烈建议设为 utf8mb4 以支持表情符和全 Emoji)
cursorclass=pymysql.cursors.DictCursor, # 指定游标类型 (如:返回字典而非元组)
autocommit=True, # 是否开启自动提交 (True/False)
connect_timeout=10, # 连接超时时间 (秒)
ssl={'ssl': ...} # SSL 加密配置 (可选,用于安全连接)
)
标准生产/开发环境写法(配合环境变量与字典游标)
bash
import os
import pymysql
def get_db():
return pymysql.connect(
host=os.getenv('DB_HOST', '127.0.0.1'),
port=int(os.getenv('DB_PORT', 3306)),
user=os.getenv('DB_USER', 'root'),
password=os.getenv('DB_PASSWORD', ''),
database=os.getenv('DB_NAME', 'test_db'),
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor, # 查询结果直接返回字典 {'col': val}
autocommit=True # 写操作自动提交,免去手动 commit
)
pymysql.connect() 返回的对象如何使用?
连接建立后,需要通过连接对象创建游标(Cursor)来执行 SQL:
bash
# 1. 获取数据库连接
db = get_db()
# 2. 使用上下文管理器执行 SQL 操作
try:
with db.cursor() as cursor:
sql = "SELECT id, title FROM topics WHERE id = %s"
cursor.execute(sql, (1,))
result = cursor.fetchone()
print(result)
finally:
# 3. 必须及时关闭连接,释放数据库资源
db.close()
关键注意要点
port 必须是整型(int): 如果端口值是从 os.getenv 或配置文件中读取的字符串(如 '3306'),必须用 int('3306') 转换,否则 PyMySQL 会抛出类型错误。
编码推荐 utf8mb4: 不要使用 'utf8',因为 MySQL 的原生 utf8 是简版(最大 3 字节),遇到 Emoji或某些特殊字符会报错,utf8mb4 是最安全的选择。
资源释放(关闭连接): 长久持有 pymysql.connect() 返回的对象不关闭,会导致 MySQL 的连接池被占满(报错 Toomany connections),务必确保在代码执行完毕后显式调用 db.close(),或在高并发场景下使用连接池(如dbutils)。
host=get_env('PYTHON_DB_HOST', 'ip')...
它的含义是:"优先从系统的环境变量中读取 PYTHON_DB_HOST 的值;如果环境变量里没配置,就默认连接本地的 127.0.0.1"。
一般环境变量在项目根目录的 .env 文件 中定义
在很多 Python 项目中,开发者会在项目根目录下创建一个名为 .env 的文本文件,里面专门用来放环境变量:
bash
# .env 文件内容
PYTHON_DB_HOST=127.0.0.1
PYTHON_DB_PORT=3306
PYTHON_DB_USERNAME=root
PYTHON_DB_PASSWORD=your_password
port=int(get_env('PYTHON_DB_PORT', 3306))
为什么一定要套一层 int()?
在操作系统或 .env 文件中,所有的环境变量提取出来时本质上都是"字符串"(比如文本 "3306")。
但 PyMySQL 驱动的 connect() 函数对 port 参数有着严格的数据类型检查:它必须是一个整型数字(int)。
cursorclass=pymysql.cursors.DictCursor
它的含义是:将数据库查询结果的游标(Cursor)类型,指定为"字典游标"(DictCursor)。
默认游标 vs 字典游标(对比说明)
默认情况下(即不加这行配置),PyMySQL 会使用标准的 TupleCursor(元组游标)。
假设你的数据库 products 表里有一行数据:
id=101, name='Leather Jacket', price=99.00
- 如果不加这行配置(默认元组游标):
查询返回的结果是一个纯元组(Tuple),它只保留数据的值,丢失了列名(字段名):
bash
cursor.execute("SELECT id, name, price FROM products WHERE id = 101")
row = cursor.fetchone()
print(row)
# 输出结果: (101, 'Leather Jacket', 99.00)
# 取值时必须记住列的顺序(用下标 0, 1, 2):
product_id = row[0]
product_name = row[1]
- 加了 cursorclass=pymysql.cursors.DictCursor(字典游标):
查询返回的结果会被自动封装为一个 Python 字典(Dictionary),键(Key)就是数据库中的列名/字段名,值(Value)就是数据:
bash
cursor.execute("SELECT id, name, price FROM products WHERE id = 101")
row = cursor.fetchone()
print(row)
# 输出结果: {'id': 101, 'name': 'Leather Jacket', 'price': 99.00}
# 取值时可以直接使用字段名:
product_id = row['id']
product_name = row['name']
它的含义是:"开启自动提交模式(Auto-Commit)。只要执行了任何写数据库的操作(如 INSERT、UPDATE、DELETE),MySQL 会立刻把变动持久化保存到磁盘上,不需要你手动编写 db.commit() 代码。"
一、 什么是"事务"与"提交"?
在默认情况下,MySQL 的 InnoDB 存储引擎使用事务(Transaction)保护机制:
当你执行了一句修改命令(比如 INSERT INTO topics ...),数据库其实只是在内存缓冲区/临时事务日志里记了一笔,并没有真正确定保存。
只有当你显式执行了 db.commit()(提交),数据库才会把这笔变动正式写入磁盘数据文件。
如果中途报错或者执行了 db.rollback()(回滚),刚才执行的所有更改就会瞬间撤销,仿佛什么都没发生过。
二、 autocommit=True 的实际效果对比
假设我们要插入一条新的专题页数据:
- 如果不设置 autocommit=True(默认手动提交):
bash
with db.cursor() as cursor:
cursor.execute("INSERT INTO topics (title) VALUES ('2026热销指南')")
# ⚠️ 必须手动加上这行,数据库里的表才会真正多出这条记录!
# 如果忘了写这行,程序运行结束也不会报错,但数据库里根本没有数据!
db.commit()
- 设置了 autocommit=True(开启自动提交):
bash
with db.cursor() as cursor:
# 只要这行代码执行成功,数据库就会【立刻】写入磁盘!
cursor.execute("INSERT INTO topics (title) VALUES ('2026热销指南')")
# 不需要写 db.commit(),数据已经稳稳存进数据库了!
注意事项
涉及资金、订单等核心业务逻辑时要谨慎使用:
破坏了"多步骤原子性":假设你在做"扣减库存 + 创建订单"的操作:扣减库存成功 →\rightarrow→(由于 autocommit=True,立刻写死到数据库)创建订单失败报错 →\rightarrow→ 崩溃!因为开启了自动提交,步骤 1 已经无法自动回滚了,导致库存扣了却没生成订单。
这种需要"要么全成功,要么全失败"的多表操作,必须把 autocommit 设为 False 并手动控制事务。