在网页应用中使用Python操作MySQL,核心思路是把数据库访问逻辑完全放在服务端,前端只负责展示后端返回的数据。常见的组合是用Flask或Django搭建Web服务,再通过PyMySQL或mysql-connector等驱动连接MySQL。下面以Flask加PyMySQL为例,一步步实现连接与查询。

一、环境准备与驱动安装
开始之前需要准备好三样东西:可访问的MySQL服务、Python运行环境,以及对应的数据库驱动。PyMySQL是纯Python实现的MySQL客户端,安装简单且兼容性好,适合在网页后端使用。
使用pip安装依赖即可,建议同时装上Flask用于提供网页接口。安装完成后,先在本地命令行测试能否连通数据库,避免后续在Web层排查连接问题。示例安装命令如下:
pip install flask pymysql
如果MySQL部署在远程服务器,要确保账号开启了对应IP的访问权限,并且防火墙放通了3306端口。很多连接失败并不是代码问题,而是权限或网络配置导致的。
二、使用连接池管理数据库连接
网页请求具有并发和短促的特点,每次请求都新建连接会带来明显开销。更好的方式是使用连接池,在应用启动时创建一批连接,请求到来时借出,处理完归还。PyMySQL本身不带池化功能,可以借助DBUtils库实现。
下面代码演示如何用DBUtils的PooledDB包装PyMySQL,生成全局连接池。这样在多个路由函数中都能稳定获取连接,而不会把MySQL的最大连接数打满。
from dbutils.pooled_db import PooledDB
import pymysql
# 创建连接池,maxconnections控制最大连接数
pool = PooledDB(
creator=pymysql,
maxconnections=10,
mincached=2,
host='127.0.0.1',
port=3306,
user='root',
password='your_password',
database='test_db',
charset='utf8mb4'
)
def get_conn():
# 从池中获取一个连接
return pool.connection()
连接池参数需要根据实际访问量调整。如果网页流量小,mincached设1到2即可;若并发高,可适当提升maxconnections,但别超过MySQL服务端设置的上限。使用完连接后调用close方法,实际是归还给池而非真正断开。
三、在Flask路由中执行查询
有了连接池,就可以在Flask的视图函数里写查询逻辑。注意密码等敏感信息不要硬编码,应从环境变量读取。下面例子提供两个路由:一个列出用户表数据,一个按ID查询。
查询时务必使用参数化占位符,PyMySQL用%s作为占位符,能有效防止SQL注入。查询结果通过fetchall转为元组列表,再简单渲染成HTML返回给浏览器。
from flask import Flask, request, render_template_string
import os
from dbutils.pooled_db import PooledDB
import pymysql
app = Flask(__name__)
pool = PooledDB(
creator=pymysql,
maxconnections=10,
host='127.0.0.1',
user=os.getenv('DB_USER', 'root'),
password=os.getenv('DB_PASS', 'your_password'),
database='test_db',
charset='utf8mb4'
)
@app.route('/users')
def list_users():
conn = pool.connection()
try:
with conn.cursor() as cur:
cur.execute('SELECT id, name, email FROM users')
rows = cur.fetchall()
return render_template_string(
'<table><tr><th>ID</th><th>姓名</th><th>邮箱</th></tr>'
'{% for r in rows %}<tr><td>{{r[0]}}</td><td>{{r[1]}}</td><td>{{r[2]}}</td></tr>{% endfor %}'
'</table>',
rows=rows
)
finally:
conn.close()
@app.route('/user')
def get_user():
uid = request.args.get('id')
conn = pool.connection()
try:
with conn.cursor() as cur:
# 参数化查询防止注入
cur.execute('SELECT name, email FROM users WHERE id=%s', (uid,))
row = cur.fetchone()
return {'name': row[0], 'email': row[1]} if row else {'error': 'not found'}
finally:
conn.close()
if __name__ == '__main__':
app.run(debug=True)
上面的代码把查询接口分成了页面展示和JSON接口两种形式,实际项目中可按照前后端分离或模板渲染的需要自行调整。finally块保证连接一定归还,避免池资源泄漏。
四、插入与更新操作的事务处理
写操作相比查询多了一个事务提交环节。PyMySQL默认不会自动提交,执行INSERT或UPDATE后必须调用commit,否则数据不会真正写入。下面示例展示一次带事务的插入。
如果插入过程出现异常,应当回滚以保证数据一致性。这种写法在网页下单、注册等场景尤为重要,可以防止半成功状态。
@app.route('/add', methods=['POST'])
def add_user():
name = request.form.get('name')
email = request.form.get('email')
conn = pool.connection()
try:
with conn.cursor() as cur:
sql = 'INSERT INTO users (name, email) VALUES (%s, %s)'
cur.execute(sql, (name, email))
conn.commit()
return '添加成功'
except Exception as e:
conn.rollback()
return '添加失败: ' + str(e)
finally:
conn.close()
对于高并发写入,还可以考虑在MySQL侧开启合适的事务隔离级别,或者把批量插入合并成一条多值语句,减少网络往返。网页端则应注意对用户输入做基础校验,降低脏数据进入库中的概率。
五、常见错误与排查要点
初学者常遇到两类报错:一类是Access denied,通常是账号权限或密码错误;另一类是Can't connect to MySQL server,多为地址、端口或防火墙问题。先在命令行用同一账号连一次,能快速定位是不是代码层面的毛病。
还有人把数据库驱动直接在前端用JavaScript引入,试图让浏览器连MySQL,这既不安全也不可能,因为MySQL协议不开放给网页跨域直连。正确架构一定是浏览器访问Python网页服务,由服务端代管数据库通信。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| Access denied for user | 密码错误或权限不足 | 核对账号、授权主机范围 |
| Can't connect to MySQL | 服务未启动或网络不通 | 检查端口与防火墙 |
| 游标取不到数据 | 未commit或SQL条件不匹配 | 确认事务提交与参数 |
把以上环节串起来,就能在Python网页版中稳定连接MySQL并完成查询操作。后续可引入ORM如SQLAlchemy,进一步减少手写SQL的成本,但底层连接与事务原则是一致的。
PythonMySQLweb_database修改时间:2026-08-02 21:27:36