【保姆级喂饭教程】python基于mysql-connector-python的数据库操作通用封装类(连接池版)

目录

在使用mysql-connector-python连接MySQL数据库的时候,如同Java中的jdbc一般,每条sql需要创建和删除连接,很自然就想到写一个抽象方法,但是找了找没有官方标准的,或者使用SQLAlchemy等类似的orm框架,于是调试deepseek写了一个

项目背景:【保姆级喂饭教程】uv教程一文讲透:安装,创建,配置,工具,命令

项目环境

安装库,
【沉浸式解决问题】mysql-connector-python连接数据库:RuntimeError: Failed raising error.

bash 复制代码
uv add mysql-connector-python==8.0.33

目录,init文件为空

一、db_config.py

python 复制代码
class DBConfig:
    """数据库配置基类"""

    @classmethod
    def get_config(cls, name: str) -> dict:
        """获取指定数据库配置"""
        return getattr(cls, name).value


class MySQLConfig(DBConfig):
    """MySQL数据库配置"""

    # 基础配置模板
    BASE = {
        "pool_name": "mysql_pool",
        "pool_size": 10,
        "pool_reset_session": True,
        "charset": "utf8mb4",
        "autocommit": False
    }

    # 具体数据库实例配置
    PYTHON_DB = {
        **BASE,
        "host": "127.0.0.1",
        "port": 3306,
        "user": "python",
        "password": "python",
        "database": "test-python"
    }

    LOG_DB = {
        **BASE,
        "host": "log-db.example.com",
        "port": 3307,
        "user": "log_user",
        "password": "log_password",
        "database": "app_logs"
    }

二、mysql_executor.py

python 复制代码
"""
MySQL 数据库连接池执行器
提供安全、高效的数据库操作接口,支持连接池、事务管理和批量操作
"""

from mysql.connector import pooling, Error
from typing import Union, List, Tuple, Dict, Any


class MySQLExecutor:
    """
    MySQL 数据库操作通用封装类(连接池版)

    特性:
    1. 基于连接池实现高效连接管理
    2. 支持自动和手动事务控制
    3. 提供查询、执行、批量操作等多种方法
    4. 完善的异常处理和资源管理
    5. 详细的日志记录

    使用示例:
    with MySQLExecutor(config) as executor:
        # 执行查询
        results = executor.query("SELECT * FROM users WHERE age > %s", (25,))

        # 执行写入操作
        executor.execute("UPDATE users SET status = 'active' WHERE id = %s", (1,))

        # 批量操作
        executor.batch_execute("INSERT INTO logs (message) VALUES (%s)", [('log1',), ('log2',)])
    """

    def __init__(self, config: Dict[str, Any]):
        """
        初始化数据库执行器

        参数:
            config: 数据库配置字典,必须包含连接池相关参数
                    示例:
                    {
                        "pool_name": "mysql_pool",
                        "pool_size": 10,
                        "host": "127.0.0.1",
                        "port": 3306,
                        "user": "root",
                        "password": "password",
                        "database": "test_db"
                    }

        异常:
            ConnectionError: 如果连接池创建失败
        """
        self.config = config
        self.pool = self._create_pool()
        self.active_connection = None  # 当前活动连接(用于事务)

    def _create_pool(self) -> pooling.MySQLConnectionPool:
        """
        创建数据库连接池

        返回:
            pooling.MySQLConnectionPool: MySQL连接池实例

        异常:
            ConnectionError: 如果连接池创建失败
        """
        try:
            print(f"正在创建MySQL连接池: {self.config.get('pool_name', 'unnamed_pool')}")
            return pooling.MySQLConnectionPool(**self.config)
        except Error as e:
            error_msg = f"创建MySQL连接池失败: {e}"
            print(error_msg)
            raise ConnectionError(error_msg) from e

    def __enter__(self):
        """
        支持with上下文管理
        返回执行器实例本身
        """
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        退出上下文时自动关闭活动连接
        """
        self.close_active_connection()

    def connection(self):
        """
        返回一个连接上下文管理器

        使用示例:
        with executor.connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute("SELECT * FROM table")
                results = cursor.fetchall()
        """
        return self._ConnectionContext(self)

    class _ConnectionContext:
        """
        连接上下文管理器内部类
        用于自动管理连接的获取和释放
        """

        def __init__(self, executor):
            self.executor = executor
            self.conn = None

        def __enter__(self) -> pooling.PooledMySQLConnection:
            """进入上下文时从连接池获取连接"""
            try:
                self.conn = self.executor.get_connection()
                return self.conn
            except Error as e:
                error_msg = f"获取数据库连接失败: {e}"
                print(error_msg)
                raise ConnectionError(error_msg) from e

        def __exit__(self, exc_type, exc_val, exc_tb):
            """退出上下文时关闭连接"""
            if self.conn and self.conn.is_connected():
                try:
                    self.conn.close()
                except Error as e:
                    print(f"关闭数据库连接时出错: {e}")

    def get_connection(self) -> pooling.PooledMySQLConnection:
        """
        从连接池获取一个新的数据库连接

        返回:
            pooling.PooledMySQLConnection: 数据库连接对象

        注意:
            使用后需要手动关闭连接,推荐使用connection()上下文管理器
        """
        return self.pool.get_connection()

    def close_active_connection(self):
        """
        关闭当前活动连接(如果存在)
        主要用于清理事务连接
        """
        if self.active_connection and self.active_connection.is_connected():
            try:
                self.active_connection.close()
                self.active_connection = None
            except Error as e:
                print(f"关闭活动连接时出错: {e}")

    def start_transaction(self):
        """
        开始一个新的事务

        异常:
            ConnectionError: 如果获取连接失败
        """
        try:
            if not self.active_connection or not self.active_connection.is_connected():
                self.active_connection = self.get_connection()
            self.active_connection.start_transaction()
            print("事务已开始")
        except Error as e:
            error_msg = f"开始事务失败: {e}"
            print(error_msg)
            raise ConnectionError(error_msg) from e

    def commit(self):
        """
        提交当前事务并关闭活动连接

        异常:
            ConnectionError: 如果提交失败或没有活动事务
        """
        if not self.active_connection:
            print("警告: 尝试提交但无活动事务")
            return

        try:
            self.active_connection.commit()
            print("事务已提交")
        except Error as e:
            error_msg = f"提交事务失败: {e}"
            print(error_msg)
            raise ConnectionError(error_msg) from e
        finally:
            self.close_active_connection()

    def rollback(self):
        """
        回滚当前事务并关闭活动连接

        异常:
            ConnectionError: 如果回滚失败
        """
        if not self.active_connection:
            print("警告: 尝试回滚但无活动事务")
            return

        try:
            self.active_connection.rollback()
            print("事务已回滚")
        except Error as e:
            error_msg = f"回滚事务失败: {e}"
            print(error_msg)
            raise ConnectionError(error_msg) from e
        finally:
            self.close_active_connection()

    def query(
            self,
            sql: str,
            params: Union[Tuple, List, None] = None,
            dictionary: bool = False
    ) -> Union[List[Tuple], List[Dict]]:
        """
        执行查询语句(SELECT)

        参数:
            sql: SQL查询语句
            params: 查询参数(可选)
            dictionary: 是否返回字典格式结果(默认为元组)

        返回:
            查询结果列表(元组或字典格式)

        异常:
            DatabaseError: 如果查询执行失败
        """
        try:
            with self.connection() as conn:
                with conn.cursor(dictionary=dictionary) as cursor:
                    cursor.execute(sql, params)
                    return cursor.fetchall()
        except Error as e:
            error_msg = f"查询执行失败: {e}\nSQL: {sql}\n参数: {params}"
            print(error_msg)
            raise DatabaseError(error_msg) from e

    def execute(
            self,
            sql: str,
            params: Union[Tuple, List, None] = None,
            commit: bool = True
    ) -> int:
        """
        执行非查询语句(INSERT/UPDATE/DELETE)

        参数:
            sql: SQL操作语句
            params: 操作参数(可选)
            commit: 是否自动提交事务(默认为True)

        返回:
            受影响的行数

        异常:
            DatabaseError: 如果操作执行失败
        """
        try:
            with self.connection() as conn:
                with conn.cursor() as cursor:
                    cursor.execute(sql, params)
                    affected_rows = cursor.rowcount
                    if commit:
                        conn.commit()
                    return affected_rows
        except Error as e:
            error_msg = f"操作执行失败: {e}\nSQL: {sql}\n参数: {params}"
            print(error_msg)
            raise DatabaseError(error_msg) from e

    def batch_execute(
            self,
            sql: str,
            params_list: List[Union[Tuple, List]],
            commit: bool = True
    ) -> int:
        """
        批量执行操作(高效)

        参数:
            sql: SQL操作语句
            params_list: 参数列表
            commit: 是否提交事务(默认为True)

        返回:
            受影响的总行数

        异常:
            DatabaseError: 如果批量操作失败
            ValueError: 如果参数列表为空
        """
        if not params_list:
            raise ValueError("参数列表不能为空")

        try:
            with self.connection() as conn:
                with conn.cursor() as cursor:
                    cursor.executemany(sql, params_list)
                    affected_rows = cursor.rowcount
                    if commit:
                        conn.commit()
                    return affected_rows
        except Error as e:
            error_msg = f"批量操作失败: {e}\nSQL: {sql}\n参数数量: {len(params_list)}"
            print(error_msg)

            # 尝试回滚事务
            try:
                if conn and conn.is_connected():
                    conn.rollback()
            except Error as rollback_err:
                print(f"回滚批量操作失败: {rollback_err}")

            raise DatabaseError(error_msg) from e

    def execute_many(
            self,
            sql_commands: List[str],
            params_list: List[Union[Tuple, List, None]] = None,
            commit: bool = True
    ) -> int:
        """
        执行多个SQL命令(可包含不同操作)

        参数:
            sql_commands: SQL命令列表
            params_list: 参数列表(可选,默认为None)
            commit: 是否提交事务(默认为True)

        返回:
            受影响的总行数

        异常:
            DatabaseError: 如果执行失败
            ValueError: 如果命令和参数长度不匹配
        """
        if params_list is None:
            params_list = [None] * len(sql_commands)

        if len(sql_commands) != len(params_list):
            raise ValueError(f"SQL命令({len(sql_commands)})和参数列表({len(params_list)})长度不一致")

        try:
            with self.connection() as conn:
                with conn.cursor() as cursor:
                    total_affected = 0
                    for i, (sql, params) in enumerate(zip(sql_commands, params_list)):
                        try:
                            cursor.execute(sql, params)
                            total_affected += cursor.rowcount
                        except Error as e:
                            # 记录具体哪个命令失败
                            error_msg = f"执行第 {i + 1} 条命令失败: {e}\nSQL: {sql}\n参数: {params}"
                            print(error_msg)
                            raise DatabaseError(error_msg) from e

                    if commit:
                        conn.commit()
                    return total_affected
        except Error as e:
            # 回滚整个事务
            try:
                if conn and conn.is_connected():
                    conn.rollback()
            except Error as rollback_err:
                print(f"回滚操作失败: {rollback_err}")

            raise DatabaseError(f"多命令执行失败: {e}") from e


# 自定义异常类,提供更清晰的错误分类
class DatabaseError(Exception):
    """数据库操作异常基类"""
    pass


class ConnectionError(DatabaseError):
    """数据库连接相关异常"""
    pass

三、test/main.py

python 复制代码
from mysql.db_config import MySQLConfig
from mysql.mysql_executor import MySQLExecutor, ConnectionError, DatabaseError

# 获取数据库配置
db_config = MySQLConfig.get_config("PYTHON_DB")

try:
    # 创建执行器(使用with上下文确保资源清理)
    with MySQLExecutor(db_config) as executor:
        print("=" * 50)
        print("示例1: 基本查询")
        print("=" * 50)

        try:
            # 执行查询 - 返回字典格式结果
            users = executor.query(
                "SELECT * FROM users WHERE age > %s",
                (25,),
                dictionary=True
            )
            print(f"查询成功,获取到 {len(users)} 条记录")
            if users:
                print(f"第一条记录: {users[0]}")
        except DatabaseError as e:
            print(f"查询操作失败: {e}")
            # 在实际应用中,这里可以记录日志或执行恢复操作

        print("\n" + "=" * 50)
        print("示例2: 插入数据")
        print("=" * 50)

        try:
            # 插入新用户
            new_user = ("Alice", "alice@example.com", 30)
            insert_sql = "INSERT INTO users (name, email, age) VALUES (%s, %s, %s)"
            affected = executor.execute(insert_sql, new_user)
            print(f"插入成功,影响行数: {affected}")
        except DatabaseError as e:
            print(f"插入操作失败: {e}")

        print("\n" + "=" * 50)
        print("示例3: 批量插入")
        print("=" * 50)

        try:
            # 批量插入用户
            users_data = [
                ("Bob", "bob@example.com", 28),
                ("Charlie", "charlie@example.com", 35),
                ("David", "david@example.com", 42)
            ]
            insert_sql = "INSERT INTO users (name, email, age) VALUES (%s, %s, %s)"

            # 批量执行
            batch_affected = executor.batch_execute(insert_sql, users_data)
            print(f"批量插入成功,总影响行数: {batch_affected}")
        except (DatabaseError, ValueError) as e:
            print(f"批量插入失败: {e}")

        print("\n" + "=" * 50)
        print("示例4: 事务处理")
        print("=" * 50)

        try:
            # 开始事务
            executor.start_transaction()
            print("事务已开始")

            try:
                # 事务内操作1:更新用户
                update_sql = "UPDATE users SET age = %s WHERE id = %s"
                executor.execute(update_sql, (31, 1), commit=False)
                print("用户更新成功")

                # 事务内操作2:插入日志
                log_sql = "INSERT INTO activity_log (user_id, action) VALUES (%s, %s)"
                executor.execute(log_sql, (1, "age_update"), commit=False)
                print("日志插入成功")

                # 查询事务内数据
                user_data = executor.query(
                    "SELECT * FROM users WHERE id = %s",
                    (1,),
                    dictionary=True
                )
                print(f"事务内用户数据: {user_data}")

                # 提交事务
                executor.commit()
                print("事务操作成功完成")

            except DatabaseError as e:
                # 事务内部操作失败,回滚事务
                print(f"事务内操作失败: {e}")
                executor.rollback()
                print("已回滚事务")
                raise  # 继续向上抛出异常

        except (DatabaseError, ConnectionError) as e:
            print(f"事务处理失败: {e}")

        print("\n" + "=" * 50)
        print("示例5: 复杂操作(多个SQL命令)")
        print("=" * 50)

        try:
            # 转账操作(多个SQL命令)
            sql_commands = [
                "UPDATE accounts SET balance = balance - 100 WHERE id = 1",
                "UPDATE accounts SET balance = balance + 100 WHERE id = 2",
                "INSERT INTO transactions (from_acc, to_acc, amount) VALUES (1, 2, 100)"
            ]

            # 执行多个命令
            total_affected = executor.execute_many(sql_commands)
            print(f"转账操作完成,总影响行数: {total_affected}")

        except (DatabaseError, ValueError) as e:
            print(f"多命令执行失败: {e}")

        print("\n" + "=" * 50)
        print("示例6: 直接使用连接上下文")
        print("=" * 50)

        try:
            # 直接使用连接上下文
            with executor.connection() as conn:
                with conn.cursor(dictionary=True) as cursor:
                    cursor.execute("SELECT * FROM users WHERE status = 'active'")
                    active_users = cursor.fetchall()
                    print(f"活跃用户数量: {len(active_users)}")

                # 同一个连接中执行另一个操作
                with conn.cursor() as cursor:
                    cursor.execute("UPDATE users SET last_login = NOW() WHERE status = 'active'")
                    conn.commit()
                    print(f"更新了 {cursor.rowcount} 个用户的登录时间")

        except (ConnectionError, DatabaseError) as e:
            print(f"连接上下文操作失败: {e}")

except ConnectionError as e:
    print(f"数据库连接初始化失败: {e}")
    # 在实际应用中,这里应该进行更严格的错误处理
finally:
    print("所有数据库操作完成")
相关推荐
NocoBase4 分钟前
6 个替代飞书多维表格的开源无代码数据库工具
数据库·开源·数据可视化
G_H_S_3_10 分钟前
【网络运维】Linux:MariaDB 数据库介绍及管理
linux·运维·网络·数据库
LLLLYYYRRRRRTT11 分钟前
MariaDB 数据库管理与web服务器
前端·数据库·mariadb
袁袁袁袁满33 分钟前
基于Python爬虫实战:获取财经股票数据
爬虫·python·ai编程
大模型真好玩42 分钟前
深入浅出LangChain AI Agent智能体开发教程(七)—LangChain多智能体浏览器自动化
人工智能·python·mcp
Kan先生1 小时前
Python调用Openai的Function calling功能—源码
python·openai
ClouGence2 小时前
构建秒级响应的实时数据架构
数据库·kafka
码界筑梦坊2 小时前
97-基于Python的大众点评数据分析预测系统
开发语言·python·数据分析
IT小番茄2 小时前
解决 MySQL 查询速度缓慢的问题
mysql
技术老金2 小时前
我为什么又开始手写Agent框架了?从CrewAI和LangGraph的局限谈起
人工智能·python