生成专题页Blog--建立并返回 MySQL 数据库连接

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

  1. 如果不加这行配置(默认元组游标):
    查询返回的结果是一个纯元组(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]
  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 的实际效果对比

假设我们要插入一条新的专题页数据:

  1. 如果不设置 autocommit=True(默认手动提交):
bash 复制代码
with db.cursor() as cursor:
    cursor.execute("INSERT INTO topics (title) VALUES ('2026热销指南')")

# ⚠️ 必须手动加上这行,数据库里的表才会真正多出这条记录!
# 如果忘了写这行,程序运行结束也不会报错,但数据库里根本没有数据!
db.commit()
  1. 设置了 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 并手动控制事务。

相关推荐
金銀銅鐵2 小时前
[Python] 借助 turtle 逐字展示唐诗《金缕衣》
python
Blossom i3 小时前
大数据预处理与采集实验一:使用Python操作MySQL数据库
数据库·mysql
InfinitePlus3 小时前
Docker MySQL搭建一主一从
mysql·docker
Python大数据分析@4 小时前
使用大模型MCP采集数据,爬虫已经无门槛
python·网络爬虫
quantdash_cc4 小时前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash
65岁退休Coder5 小时前
LangChain v1.3.4 笔记 - 07 补充:链式调用 LCEL
后端·python·langchain
卷无止境5 小时前
FastAPI 部署在 Nginx 后面到底该怎么配
后端·python
半亩码田5 小时前
C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路
开发语言·python·c#
坐吃山猪6 小时前
Docker07-MySQL
mysql·docker·容器
Wzx1980126 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker