云端服务器使用指南:利用Python操作mysql数据库

文章目录


前言:从MySQL命令到Python自动化

在上一篇博客中,我们系统梳理了MySQL的核心命令语句集------从基础的SELECT查询、INSERT插入,到复杂的JOIN联表、GROUP BY分组,再到表结构操作的CREATE TABLEALTER TABLE。这些命令是操作MySQL的"基石",但在实际开发中,我们很少直接在MySQL终端手动敲命令,而是需要更高效的自动化流程。

这时候就需要编程语言与数据库的联动 ------Python作为数据处理和后端开发的"万金油",凭借简洁语法和丰富生态,成为操作MySQL的首选工具之一。而PyMySQL作为Python生态中最流行的MySQL第三方驱动,以轻量、高性能、API简洁的特点被广泛使用。本文将从"Python(PyMySQL)连接MySQL"的底层原理讲起,手把手教你用PyMySQL实现MySQL的CRUD(增删改查)、事务处理等核心操作,让数据库操作真正融入代码自动化流程。

一、Python调用MySQL的底层原理

Python本身无法直接与MySQL通信,核心依赖**"数据库驱动"** 作为"中间翻译官",而PyMySQL就是这个"翻译官"的主流选择。整个通信流程可拆解为以下关键环节:

1. 核心角色:PyMySQL驱动

PyMySQL是纯Python编写的MySQL驱动库,无需依赖其他C扩展,其核心作用是:

  • 协议转换:将Python代码中的操作指令,转换成MySQL服务器能识别的TCP/IP协议数据包。
  • 结果解析:将MySQL返回的二进制结果(如查询数据、执行状态),解析成Python易处理的列表、元组、字典等数据结构。

相比MySQL官方驱动mysql-connector-pythonPyMySQL的优势在于:

  • 纯Python实现,安装无需编译,跨平台兼容性更强;
  • 性能更优,尤其在批量数据操作场景下;
  • 社区活跃,问题解决资源更丰富,API设计更贴合Python开发者习惯。

2. 连接流程:5步建立通信

Python(PyMySQL)操作MySQL的通用流程遵循"建立连接→创建工具→执行操作→处理结果→释放资源"的逻辑,具体步骤如下:

  1. 安装驱动 :通过pip安装PyMySQL库。
  2. 建立连接 :调用pymysql.connect(),传入MySQL地址、用户名、密码、目标数据库名等参数,创建Connection连接对象------这是Python与MySQL之间的"数据通道"。
  3. 创建游标 :通过连接对象的cursor()方法创建Cursor游标对象------游标是执行SQL语句的"工具",负责发送SQL到MySQL服务器,并接收返回结果。
  4. 执行SQL与处理结果
    • 读操作(SELECT):用游标execute()执行SQL,通过fetchone()/fetchmany()/fetchall()获取结果;
    • 写操作(INSERT/UPDATE/DELETE):执行SQL后需调用connection.commit()提交事务,确保数据写入数据库。
  5. 释放资源 :操作完成后,先关闭游标(cursor.close()),再关闭连接(connection.close()),避免占用MySQL连接资源。

二、实战:用PyMySQL操作MySQL的全套示例

在开始前,请完成环境准备,确保流程顺畅:

  1. 启动MySQL服务(本地服务填localhost,远程服务填对应IP);
  2. 安装PyMySQL:执行命令 pip install pymysql
  3. 提前创建测试数据库:在MySQL终端执行 CREATE DATABASE IF NOT EXISTS test_db DEFAULT CHARSET utf8mb4;(避免中文乱码)。

示例1:基础连接------打通Python与MySQL的通道

连接是所有操作的前提

需注意:实际开发中不要硬编码数据库密码 (建议存在配置文件或环境变量中,如os.getenv("MYSQL_PASSWORD"))。

python 复制代码
import pymysql
from pymysql import Error

def connect_mysql():
    """用PyMySQL连接MySQL的通用函数"""
    connection = None  # 初始化连接对象,避免后续报错
    try:
        # 1. 建立连接:传入MySQL配置参数
        connection = pymysql.connect(
            host='localhost',        # MySQL服务地址(本地默认localhost)
            database='test_db',      # 目标数据库名
            user='root',             # MySQL用户名(默认管理员账号为root)
            password='your_password' # 替换为你的MySQL密码(如无密码可传空字符串)
        )
        
        # 2. 验证连接是否成功
        if connection.open:  # connection.open判断连接是否存活
            db_version = connection.get_server_info()  # 获取MySQL服务版本
            print(f"✅ 成功连接MySQL,服务版本:{db_version}")
            
            # 查询当前连接的数据库名称,验证是否正确指向test_db
            cursor = connection.cursor()
            cursor.execute("SELECT DATABASE();")  # 执行SQL查询
            current_db = cursor.fetchone()        # 获取查询结果(元组类型)
            print(f"🔗 当前连接的数据库:{current_db[0]}")

    except Error as e:
        # 捕获连接异常(如密码错误、数据库不存在、服务未启动)
        print(f"❌ 连接MySQL失败!错误信息:{e}")
    finally:
        # 3. 关闭连接与游标,释放资源
        if connection and connection.open:
            cursor.close()    # 先关游标
            connection.close()# 再关连接
            print("\n🔌 MySQL连接已关闭")

# 调用函数测试连接
connect_mysql()

代码关键说明

  • from pymysql import Error:捕获PyMySQL所有操作(连接、执行SQL)的异常,方便定位问题;
  • connection.open:替代is_connected()(部分旧版本PyMySQL不支持后者),更稳定地判断连接状态;
  • cursor.fetchone():获取查询结果的"第一条数据",返回元组(如('test_db',)),需通过索引[0]取具体值。

示例2:创建数据表------定义数据存储结构

以创建user表为例(包含用户ID、姓名、年龄、邮箱等常见字段),需注意字段约束(如主键自增、邮箱唯一)。

python 复制代码
import pymysql
from pymysql import Error

def create_user_table():
    """在test_db数据库中创建user表"""
    connection = None
    try:
        connection = pymysql.connect(
            host='localhost',
            database='test_db',
            user='root',
            password='your_password'
        )
        
        if connection.open:
            cursor = connection.cursor()
            # 定义创建表的SQL:IF NOT EXISTS避免重复创建报错
            create_table_sql = """
            CREATE TABLE IF NOT EXISTS user (
                id INT AUTO_INCREMENT PRIMARY KEY,  # 主键(唯一标识),自增
                name VARCHAR(50) NOT NULL,          # 姓名,非空(不允许空值)
                age INT DEFAULT 0,                  # 年龄,默认值0(未填时自动补0)
                email VARCHAR(100) UNIQUE,          # 邮箱,唯一(避免重复注册)
                create_time DATETIME DEFAULT CURRENT_TIMESTAMP  # 创建时间,默认当前时间
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;  # InnoDB支持事务,utf8mb4支持emoji
            """
            cursor.execute(create_table_sql)  # 执行创建表的SQL
            print("✅ user表创建成功(或已存在)")

    except Error as e:
        print(f"❌ 创建表失败!错误信息:{e}")
    finally:
        if connection and connection.open:
            cursor.close()
            connection.close()

create_user_table()

示例3:插入数据------单条与批量插入

插入数据分"单条插入"和"批量插入",批量插入用executemany()效率更高(减少Python与MySQL的网络交互次数)。

python 复制代码
import pymysql
from pymysql import Error

def insert_user_data():
    """向user表插入数据(单条+批量)"""
    connection = None
    try:
        connection = pymysql.connect(
            host='localhost',
            database='test_db',
            user='root',
            password='your_password'
        )
        
        if connection.open:
            cursor = connection.cursor()
            
            # 1. 单条插入:用%s作为占位符(关键!避免SQL注入)
            single_insert_sql = "INSERT INTO user (name, age, email) VALUES (%s, %s, %s);"
            single_user = ("张三", 25, "zhangsan@example.com")  # 数据顺序与占位符对应
            cursor.execute(single_insert_sql, single_user)
            print(f"✅ 单条插入成功,新增用户ID:{cursor.lastrowid}")  # lastrowid获取自增主键
            
            # 2. 批量插入:executemany()接收"SQL语句+数据列表"
            batch_insert_sql = "INSERT INTO user (name, age, email) VALUES (%s, %s, %s);"
            batch_users = [
                ("李四", 28, "lisi@example.com"),
                ("王五", 22, "wangwu@example.com"),
                ("赵六", 30, "zhaoliu@example.com")
            ]
            cursor.executemany(batch_insert_sql, batch_users)
            print(f"✅ 批量插入成功,共插入{cursor.rowcount}条数据")  # rowcount获取影响行数
            
            # 关键:写操作必须提交事务!否则数据仅在当前连接可见,未真正写入数据库
            connection.commit()
            print("✅ 事务提交成功")

    except Error as e:
        # 出错时回滚事务,避免数据不一致(如部分插入成功、部分失败)
        if connection:
            connection.rollback()
        print(f"❌ 插入数据失败!已回滚,错误信息:{e}")
    finally:
        if connection and connection.open:
            cursor.close()
            connection.close()

insert_user_data()

安全与效率提醒

  • 必须用%s作为占位符,禁止用f-string%格式化SQL(如f"INSERT INTO user VALUES ({name})")------后者会导致SQL注入攻击(比如用户输入' OR 1=1 #会篡改SQL逻辑);
  • 批量插入时,executemany()比循环调用execute()效率高10倍以上,建议优先使用。

示例4:查询数据------获取并处理结果

查询是最常用的操作,PyMySQL游标提供3种获取结果的方法,需根据数据量选择:

  • fetchone():获取第一条结果(适合单条数据查询,如查单个用户);
  • fetchmany(size):获取前size条结果(适合分页查询,如查前10条数据);
  • fetchall():获取所有结果(适合小批量数据,海量数据用此方法会占用大量内存)。
python 复制代码
import pymysql
from pymysql import Error

def query_user_data():
    """查询user表数据(普通查询+条件查询+排序)"""
    connection = None
    try:
        connection = pymysql.connect(
            host='localhost',
            database='test_db',
            user='root',
            password='your_password'
        )
        
        if connection.open:
            cursor = connection.cursor()
            
            # 1. 普通查询:查询所有用户,按年龄倒序
            print("=== 所有用户数据(按年龄倒序) ===")
            all_query_sql = "SELECT id, name, age, email, create_time FROM user ORDER BY age DESC;"
            cursor.execute(all_query_sql)
            all_users = cursor.fetchall()  # 获取所有结果(列表,每个元素是元组)
            for user in all_users:
                # 元组索引对应SQL查询的字段顺序:id(0)、name(1)、age(2)、email(3)、create_time(4)
                print(f"ID: {user[0]}, 姓名: {user[1]}, 年龄: {user[2]}, 邮箱: {user[3]}, 创建时间: {user[4]}")
            
            # 2. 条件查询:查询年龄>25的用户(用%s传参,避免硬编码)
            print("\n=== 年龄>25的用户(取前2条) ===")
            condition_sql = "SELECT name, age FROM user WHERE age > %s;"
            # 注意:参数必须是元组(即使只有1个参数,也要加逗号,否则会被当作字符串处理)
            cursor.execute(condition_sql, (25,))
            filtered_users = cursor.fetchmany(2)  # 获取前2条结果
            for user in filtered_users:
                print(f"姓名: {user[0]}, 年龄: {user[1]}")
            
            # 3. 单条查询:查询姓名为"张三"的用户
            print("\n=== 姓名为'张三'的用户 ===")
            single_sql = "SELECT id, email FROM user WHERE name = %s;"
            cursor.execute(single_sql, ("张三",))
            zhangsan = cursor.fetchone()  # 获取第一条结果(无结果则返回None)
            if zhangsan:
                print(f"找到用户:ID={zhangsan[0]}, 邮箱={zhangsan[1]}")
            else:
                print("未找到姓名为'张三'的用户")

    except Error as e:
        print(f"❌ 查询数据失败!错误信息:{e}")
    finally:
        if connection and connection.open:
            cursor.close()
            connection.close()

query_user_data()

示例5:更新与删除------高危操作需谨慎

UPDATE(更新)和DELETE(删除)是高危操作------忘记加WHERE条件会修改/删除全表数据 !建议操作前先执行SELECT验证条件是否正确。

python 复制代码
import pymysql
from pymysql import Error

def update_and_delete_user():
    """更新和删除user表数据"""
    connection = None
    try:
        connection = pymysql.connect(
            host='localhost',
            database='test_db',
            user='root',
            password='your_password'
        )
        
        if connection.open:
            cursor = connection.cursor()
            
            # 1. 更新数据:将"张三"的年龄改为26
            update_sql = "UPDATE user SET age = %s WHERE name = %s;"
            cursor.execute(update_sql, (26, "张三"))
            print(f"✅ 更新完成,影响行数:{cursor.rowcount}")  # 若"张三"不存在,rowcount为0
            
            # 2. 删除数据:删除邮箱为"zhaoliu@example.com"的用户
            delete_sql = "DELETE FROM user WHERE email = %s;"
            cursor.execute(delete_sql, ("zhaoliu@example.com",))
            print(f"✅ 删除完成,影响行数:{cursor.rowcount}")
            
            # 提交事务(写操作必须提交,否则修改不生效)
            connection.commit()
            print("✅ 事务提交成功")

    except Error as e:
        if connection:
            connection.rollback()  # 出错回滚,恢复到操作前状态
        print(f"❌ 更新/删除失败!已回滚,错误信息:{e}")
    finally:
        if connection and connection.open:
            cursor.close()
            connection.close()

update_and_delete_user()

示例6:事务处理------确保数据一致性

事务的核心是"要么全成功,要么全失败"(ACID特性),典型场景如"转账":A用户扣钱和B用户加钱必须同时完成,否则回滚到初始状态。

python 复制代码
import pymysql
from pymysql import Error

def transfer_demo():
    """事务示例:模拟用户转账(张三给李四转100元)"""
    connection = None
    try:
        connection = pymysql.connect(
            host='localhost',
            database='test_db',
            user='root',
            password='your_password'
        )
        
        if connection.open:
            # 关键:关闭自动提交(PyMySQL默认autocommit=True,需手动改为False才能控制事务)
            connection.autocommit = False
            cursor = connection.cursor()
            
            # 前提:先给user表加"余额"字段(执行一次即可)
            # cursor.execute("ALTER TABLE user ADD balance INT DEFAULT 0;")
            # connection.commit()  # 首次加字段需提交
            
            # 转账参数:张三ID=1,李四ID=2,转账金额=100
            from_user_id = 1
            to_user_id = 2
            amount = 100
            
            # 1. 先查询张三的余额是否足够
            cursor.execute("SELECT balance FROM user WHERE id = %s;", (from_user_id,))
            from_balance = cursor.fetchone()[0]
            if from_balance < amount:
                # 手动抛异常,触发后续回滚
                raise Exception(f"张三余额不足!当前余额:{from_balance},需转账:{amount}")
            
            # 2. 执行转账操作(两步:张三扣钱,李四加钱)
            cursor.execute("UPDATE user SET balance = balance - %s WHERE id = %s;", (amount, from_user_id))
            cursor.execute("UPDATE user SET balance = balance + %s WHERE id = %s;", (amount, to_user_id))
            
            # 3. 提交事务(所有步骤成功后再提交)
            connection.commit()
            print("✅ 转账成功!")

    except Exception as e:
        # 任何一步出错,都回滚事务
        if connection:
            connection.rollback()
        print(f"❌ 转账失败!已回滚,错误信息:{e}")
    finally:
        if connection and connection.open:
            # 恢复自动提交默认值(避免影响其他操作)
            connection.autocommit = True
            cursor.close()
            connection.close()

transfer_demo()

三、总结:PyMySQL操作MySQL的关键要点

  1. 驱动使用PyMySQL是纯Python驱动,安装简单、性能优秀,API与官方驱动兼容,是Python操作MySQL的首选;
  2. 安全防护
    • 始终用%s作为SQL参数占位符,禁止拼接SQL字符串,避免SQL注入;
    • 数据库密码、地址等敏感信息,不要硬编码在代码中,用配置文件(如config.ini)或环境变量存储;
  3. 资源管理
    • 每次操作后必须关闭游标和连接(可改用with上下文管理器自动关闭,如with connection.cursor() as cursor:);
    • 写操作(插入/更新/删除/事务)必须调用commit(),出错及时rollback(),避免数据不一致;
  4. 结果处理
    • 海量数据查询时,避免用fetchall()(会占用大量内存),建议用fetchmany(size)分页查询,或遍历游标(for row in cursor:);
    • 查询结果是元组,可通过cursor.description获取字段名,转换为字典(如dict(zip([col[0] for col in cursor.description], row))),方便按字段名取值;
  5. 进阶方向 :若项目复杂度高(如多表关联、复杂查询),手动写SQL易出错,可升级到ORM框架(如SQLAlchemy)------通过Python类映射数据库表,用面向对象语法操作数据库,无需直接写SQL。

希望本文能帮你打通"Python(PyMySQL)+ MySQL"的实战链路,让数据库操作更高效、更安全!如果遇到问题,欢迎在评论区交流~

相关推荐
liulilittle4 分钟前
LINUX RING BUFFER TUN/TAP 1
linux·服务器·网络·c++·信息与通信·通信
Sunshine for you8 分钟前
如何用FastAPI构建高性能的现代API
jvm·数据库·python
阿贵---13 分钟前
Python Web爬虫入门:使用Requests和BeautifulSoup
jvm·数据库·python
Red丶哞43 分钟前
内网自建Postfix使用Python发送邮件
开发语言·python
路由侠内网穿透.1 小时前
本地部署开源书签管理工具 LinkAce 并实现外部访问( Linux 版本)
linux·运维·服务器·网络·网络协议·开源
rebekk1 小时前
pytorch custom op的简单介绍
人工智能·pytorch·python
道清茗1 小时前
【MySQL知识点问答题】 MySQL 配置参数和内存管理
数据库·mysql
chushiyunen1 小时前
uv使用笔记(python包的管理工具)
笔记·python·uv
曲幽1 小时前
FastAPI状态共享秘籍:别再让中间件、依赖和路由“各自为政”了!
python·fastapi·web·request·state·depends·middleware
风清扬【coder】1 小时前
Anaconda 被误删后抢救手册:数据恢复 + 环境重建应急流程
python·数据恢复·anaconda·环境重建