在Python中调用MySQL数据库存储过程时,如何传递参数?

0 阅读4分钟

一、参数类型说明

MySQL 存储过程的参数分为 3 类,Python 中传递方式各有不同:

  • IN:输入参数(默认),仅从 Python 传入 MySQL,存储过程内只读。
  • OUT:输出参数,仅从 MySQL 返回到 Python,需提前定义接收变量。
  • INOUT:输入输出参数,既传入值,又返回修改后的值。

二、完整示例代码

先在 MySQL 中创建包含 3 类参数的存储过程,再用 Python 调用:

1. 创建测试存储过程

-- 切换到你的数据库
USE test_db;

-- 存储过程:计算a+b的和(OUT),并将c乘以2返回(INOUT)
DELIMITER //
CREATE PROCEDURE calc_params(
    IN a INT,               -- 输入参数
    OUT sum_ab INT,         -- 输出参数
    INOUT c INT             -- 输入输出参数
)
BEGIN
    SET sum_ab = a + b;     -- 计算a+b(b是隐式的?修正:补充b参数)
    -- 修正:完整定义,添加b参数
    -- 重新创建正确的存储过程:
    DROP PROCEDURE IF EXISTS calc_params;
    CREATE PROCEDURE calc_params(
        IN a INT,
        IN b INT,
        OUT sum_ab INT,
        INOUT c INT
    )
    BEGIN
        SET sum_ab = a + b;       -- 输出a+b的和
        SET c = c * 2;            -- 输入输出参数:c乘以2返回
    END //
DELIMITER ;

2. Python 传递不同参数的代码

import mysql.connector
from mysql.connector import Error

def call_procedure_with_params():
    config = {
        'host': 'localhost',
        'user': 'root',
        'password': '你的密码',
        'database': 'test_db',
        'charset': 'utf8mb4'  # 避免中文乱码
    }

    connection = None
    try:
        connection = mysql.connector.connect(**config)
        cursor = connection.cursor()

        # ========== 1. 定义参数 ==========
        # IN参数:直接传值
        in_a = 10
        in_b = 20
        
        # OUT参数:初始化为None,用于接收返回值
        out_sum_ab = None
        
        # INOUT参数:先传初始值,最终接收修改后的值
        inout_c = 15  # 初始值15,存储过程会改为30

        # ========== 2. 调用存储过程(核心:参数按顺序传入元组) ==========
        # 格式:cursor.callproc(存储过程名, (参数1, 参数2, ...))
        # 参数顺序必须与存储过程定义的顺序完全一致!
        cursor.callproc('calc_params', (in_a, in_b, out_sum_ab, inout_c))

        # ========== 3. 获取返回的参数值 ==========
        # 方式1:通过 cursor.stored_results()(通用)
        for result in cursor.stored_results():
            # 输出参数和INOUT参数的结果会存在这里
            pass  # 无结果集时无需读取,参数已自动更新
        
        # 方式2:直接读取 cursor.outputs(更直观)
        # cursor.outputs 是字典,key为参数位置(从0开始),value为返回值
        # 位置对应:0→in_a, 1→in_b, 2→out_sum_ab, 3→inout_c
        out_sum_ab = cursor.outputs[2]  # 获取OUT参数值
        inout_c = cursor.outputs[3]     # 获取INOUT参数修改后的值

        # ========== 4. 打印结果 ==========
        print("参数传递结果:")
        print(f"IN参数 a = {in_a}, b = {in_b}(传入后未修改)")
        print(f"OUT参数 sum_ab(a+b)= {out_sum_ab}")
        print(f"INOUT参数 c(初始15→×2)= {inout_c}")

        connection.commit()

    except Error as e:
        print(f"错误:{e}")
        if connection:
            connection.rollback()
    finally:
        if connection and connection.is_connected():
            cursor.close()
            connection.close()

if __name__ == "__main__":
    call_procedure_with_params()

三、关键细节解释

1. IN 参数传递(最简单)

  • 传递方式:直接传入具体值(int/str/float 等),类型需与 MySQL 存储过程定义的一致。
  • 示例in_a = 10in_b = 20,直接放入 callproc 的参数元组即可。
  • 注意:MySQL 的 VARCHAR 对应 Python 的 strINT 对应 intDATETIME 可传字符串(如 '2026-01-07')或 datetime 对象。

2. OUT 参数传递

  • 传递方式:必须先定义一个变量(通常初始化为 None),放入参数元组。
  • 获取返回值
    • 方式 1:cursor.outputs[参数位置](推荐,直观),位置从 0 开始计数。
    • 方式 2:遍历 cursor.stored_results()(兼容所有版本)。
  • 注意:OUT 参数本身不接收传入的值,仅用于返回,初始值无意义(None 即可)。

3. INOUT 参数传递

  • 传递方式:先传入初始值(如 inout_c = 15),放入参数元组。
  • 获取返回值:与 OUT 参数相同,通过 cursor.outputs[位置] 获取修改后的值。
  • 核心特点:既把初始值传给存储过程,又接收存储过程修改后的值。

4. 特殊场景:传递列表/批量参数

如果需要传递多个值(如 IN (1,2,3)),可通过拼接 SQL 或使用参数化查询:

# 示例:调用存储过程,传入多个ID(IN参数)
def call_procedure_with_list():
    config = {...}  # 同前
    connection = mysql.connector.connect(**config)
    cursor = connection.cursor()
    
    # 批量ID参数
    ids = [1, 2, 3]
    # 方式:将列表转为字符串,作为IN参数传入(需确保无SQL注入风险)
    id_str = ','.join(map(str, ids))
    
    # 调用存储过程(假设存储过程接收字符串类型的ID列表)
    cursor.callproc('get_users_by_ids', (id_str,))
    
    # 读取结果
    for result in cursor.stored_results():
        print(result.fetchall())