From 06a45b363922b5790e9e61f4b152d5bb1d671940 Mon Sep 17 00:00:00 2001 From: Windpicker-owo <3431391539@qq.com> Date: Thu, 4 Dec 2025 23:30:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=AF=B9=20MySQL?= =?UTF-8?q?=20=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=92=8C=E9=85=8D=E7=BD=AE=E4=BB=A5=E4=BB=85?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20SQLite=20=E5=92=8C=20PostgreSQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/copilot-instructions.md | 4 +- README.md | 6 +- bot.py | 2 +- pyproject.toml | 5 +- requirements.txt | 2 - scripts/migrate_database.py | 109 ++++++------------ .../message_manager/batch_database_writer.py | 14 --- src/chat/message_receive/chat_stream.py | 6 - src/common/database/core/__init__.py | 1 - src/common/database/core/dialect_adapter.py | 32 +---- src/common/database/core/engine.py | 54 +-------- src/common/database/core/migration.py | 3 - src/common/database/core/models.py | 9 +- src/common/database/core/session.py | 5 +- .../database/optimization/connection_pool.py | 4 +- src/config/official_configs.py | 19 +-- src/plugin_system/utils/dependency_alias.py | 1 - template/bot_config_template.toml | 25 +--- 18 files changed, 54 insertions(+), 247 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 819189b09..50d156157 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -157,7 +157,7 @@ python __main__.py # 备用入口 **调试技巧**: - 检查 `logs/app_*.jsonl` 结构化日志 - 使用 `get_errors()` 工具查看编译错误 -- 数据库问题:查看 `data/MaiBot.db`(SQLite)或 MySQL 连接 +- 数据库问题:查看 `data/MaiBot.db`(SQLite)或 PostgreSQL 连接 ## 📋 关键约定与模式 @@ -165,7 +165,7 @@ python __main__.py # 备用入口 **全局配置**: `src/config/config.py` 的 `global_config` 单例 - 通过 TOML 文件驱动(`config/bot_config.toml`) - 支持环境变量覆盖(`.env`) -- 数据库类型切换:`database.database_type = "sqlite" | "mysql"` +- 数据库类型切换:`database.database_type = "sqlite" | "postgresql"` ### 事件系统 **Event Manager** (`src/plugin_system/core/event_manager.py`): diff --git a/README.md b/README.md index a4f532895..f4ae5e26c 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ ### 🚀 拓展功能 - 🧠 **AFC 智能对话** - 基于亲和力流,实现兴趣感知和动态关系构建 -- 🔄 **数据库切换** - 支持 SQLite 与 MySQL 自由切换,采用 SQLAlchemy 2.0 重新构建 +- 🔄 **数据库切换** - 支持 SQLite 与 PostgreSQL 自由切换,采用 SQLAlchemy 2.0 重新构建 - 🛡️ **反注入集成** - 内置一整套回复前注入过滤系统,为人格保驾护航 - 🎥 **视频分析** - 支持多种视频识别模式,拓展原版视觉 - 📅 **日程系统** - 让MoFox规划每一天 @@ -109,7 +109,7 @@ | 服务 | 描述 | | ------------ | ------------------------------------------ | | 🤖 QQ 协议端 | [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 或其他兼容协议端 | -| 🗃️ 数据库 | SQLite(默认)或 MySQL(可选) | +| 🗃️ 数据库 | SQLite(默认)或 PostgreSQL(可选) | | 🔧 管理工具 | Chat2DB(可选,用于数据库可视化管理) | --- @@ -133,7 +133,7 @@ 1. 📝 **核心配置**:编辑 `config/bot_config.toml`,设置 LLM API Key、Bot 名称等基础参数。 2. 🤖 **协议端配置**:确保使用 [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 或兼容协议端,建立稳定通信。 -3. 🗃️ **数据库配置**:选择 SQLite(默认)或配置 MySQL 数据库连接。 +3. 🗃️ **数据库配置**:选择 SQLite(默认)或配置 PostgreSQL 数据库连接。 4. 🔌 **插件配置**:在 `config/plugins/` 目录中启用或配置所需插件。 diff --git a/bot.py b/bot.py index b3c653096..f752d81ab 100644 --- a/bot.py +++ b/bot.py @@ -21,7 +21,7 @@ logger = get_logger("main") install(extra_lines=3) # 常量定义 -SUPPORTED_DATABASES = ["sqlite", "mysql", "postgresql"] +SUPPORTED_DATABASES = ["sqlite", "postgresql"] SHUTDOWN_TIMEOUT = 10.0 EULA_CHECK_INTERVAL = 2 MAX_EULA_CHECK_ATTEMPTS = 30 diff --git a/pyproject.toml b/pyproject.toml index 6f8dc92a7..be298b743 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,6 @@ dependencies = [ "pydantic>=2.12.3", "pygments>=2.19.2", "pymongo>=4.13.2", - "pymysql>=1.1.1", "pypinyin>=0.54.0", "PyYAML>=6.0", "python-dateutil>=2.9.0.post0", @@ -74,15 +73,13 @@ dependencies = [ "uvicorn>=0.35.0", "watchdog>=6.0.0", "websockets>=15.0.1", - "aiomysql>=0.2.0", "aiosqlite>=0.21.0", "inkfox>=0.1.1", "rjieba>=0.1.13", "fastmcp>=2.13.0", "mofox-wire", "jinja2>=3.1.0", - "psycopg2-binary", - "PyMySQL" + "psycopg2-binary" ] [[tool.uv.index]] diff --git a/requirements.txt b/requirements.txt index e91f9f380..cb640d6a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,8 @@ aiosqlite aiofiles -aiomysql asyncpg psycopg[binary] psycopg2-binary -PyMySQL APScheduler aiohttp aiohttp-cors diff --git a/scripts/migrate_database.py b/scripts/migrate_database.py index b5e5c30c6..9f4bf71d3 100644 --- a/scripts/migrate_database.py +++ b/scripts/migrate_database.py @@ -2,14 +2,12 @@ """数据库迁移脚本 支持在不同数据库之间迁移数据: -- SQLite <-> MySQL - SQLite <-> PostgreSQL -- MySQL <-> PostgreSQL 使用方法: python scripts/migrate_database.py --help python scripts/migrate_database.py --source sqlite --target postgresql - python scripts/migrate_database.py --source mysql --target postgresql --batch-size 5000 + python scripts/migrate_database.py --source postgresql --target sqlite --batch-size 5000 # 交互式向导模式(推荐) python scripts/migrate_database.py @@ -25,7 +23,7 @@ 实现细节: - 使用 SQLAlchemy 进行数据库连接和元数据管理 - 采用流式迁移,避免一次性加载过多数据 -- 支持 SQLite、MySQL、PostgreSQL 之间的互相迁移 +- 支持 SQLite、PostgreSQL 之间的互相迁移 - 批量插入失败时自动降级为逐行插入,最大程度保留数据 """ @@ -124,7 +122,7 @@ def get_database_config_from_toml(db_type: str) -> dict | None: """从 bot_config.toml 中读取数据库配置 Args: - db_type: 数据库类型,支持 "sqlite"、"mysql"、"postgresql" + db_type: 数据库类型,支持 "sqlite"、"postgresql" Returns: dict: 数据库配置字典,如果对应配置不存在则返回 None @@ -148,28 +146,6 @@ def get_database_config_from_toml(db_type: str) -> dict | None: sqlite_path = os.path.join(PROJECT_ROOT, sqlite_path) return {"path": sqlite_path} - elif db_type == "mysql": - return { - "host": db_config.get("mysql_host") - or config_data.get("mysql_host") - or "localhost", - "port": db_config.get("mysql_port") - or config_data.get("mysql_port") - or 3306, - "database": db_config.get("mysql_database") - or config_data.get("mysql_database") - or "maibot", - "user": db_config.get("mysql_user") - or config_data.get("mysql_user") - or "root", - "password": db_config.get("mysql_password") - or config_data.get("mysql_password") - or "", - "charset": db_config.get("mysql_charset") - or config_data.get("mysql_charset") - or "utf8mb4", - } - elif db_type == "postgresql": return { "host": db_config.get("postgresql_host") @@ -257,7 +233,7 @@ def create_engine_by_type(db_type: str, config: dict) -> Engine: """根据数据库类型创建对应的 SQLAlchemy Engine Args: - db_type: 数据库类型,支持 sqlite/mysql/postgresql + db_type: 数据库类型,支持 sqlite/postgresql config: 配置字典 Returns: @@ -266,15 +242,6 @@ def create_engine_by_type(db_type: str, config: dict) -> Engine: db_type = db_type.lower() if db_type == "sqlite": return create_sqlite_engine(config["path"]) - elif db_type == "mysql": - return create_mysql_engine( - host=config["host"], - port=config["port"], - database=config["database"], - user=config["user"], - password=config["password"], - charset=config.get("charset", "utf8mb4"), - ) elif db_type == "postgresql": return create_postgresql_engine( host=config["host"], @@ -512,7 +479,7 @@ def migrate_table_data( source_table: 源表对象 target_table: 目标表对象 batch_size: 每批次处理大小 - target_dialect: 目标数据库方言 (sqlite/mysql/postgresql) + target_dialect: 目标数据库方言 (sqlite/postgresql) row_limit: 最大迁移行数限制,None 表示不限制 Returns: @@ -738,7 +705,7 @@ class DatabaseMigrator: def _validate_database_types(self): """验证数据库类型""" - supported_types = {"sqlite", "mysql", "postgresql"} + supported_types = {"sqlite", "postgresql"} if self.source_type not in supported_types: raise ValueError(f"不支持的源数据库类型: {self.source_type}") if self.target_type not in supported_types: @@ -995,7 +962,7 @@ class DatabaseMigrator: def parse_args(): """解析命令行参数""" parser = argparse.ArgumentParser( - description="数据库迁移工具 - 在 SQLite、MySQL、PostgreSQL 之间迁移数据", + description="数据库迁移工具 - 在 SQLite、PostgreSQL 之间迁移数据", formatter_class=argparse.RawDescriptionHelpFormatter, epilog="""示例: # 从 SQLite 迁移到 PostgreSQL @@ -1008,15 +975,16 @@ def parse_args(): --target-user postgres \ --target-password your_password - # 从 SQLite 迁移到 MySQL + # 从 PostgreSQL 迁移到 SQLite python scripts/migrate_database.py \ - --source sqlite \ - --target mysql \ - --target-host localhost \ - --target-port 3306 \ - --target-database maibot \ - --target-user root \ - --target-password your_password + --source postgresql \ + --source-host localhost \ + --source-port 5432 \ + --source-database maibot \ + --source-user postgres \ + --source-password your_password \ + --target sqlite \ + --target-path data/MaiBot_backup.db # 使用交互式向导模式(推荐) python scripts/migrate_database.py @@ -1028,13 +996,13 @@ def parse_args(): parser.add_argument( "--source", type=str, - choices=["sqlite", "mysql", "postgresql"], + choices=["sqlite", "postgresql"], help="源数据库类型(不指定时,在交互模式中选择)", ) parser.add_argument( "--target", type=str, - choices=["sqlite", "mysql", "postgresql"], + choices=["sqlite", "postgresql"], help="目标数据库类型(不指定时,在交互模式中选择)", ) parser.add_argument( @@ -1053,8 +1021,8 @@ def parse_args(): # 源数据库参数(可选,默认从 bot_config.toml 读取) source_group = parser.add_argument_group("源数据库配置(可选,默认从 bot_config.toml 读取)") source_group.add_argument("--source-path", type=str, help="SQLite 数据库路径") - source_group.add_argument("--source-host", type=str, help="MySQL/PostgreSQL 主机") - source_group.add_argument("--source-port", type=int, help="MySQL/PostgreSQL 端口") + source_group.add_argument("--source-host", type=str, help="PostgreSQL 主机") + source_group.add_argument("--source-port", type=int, help="PostgreSQL 端口") source_group.add_argument("--source-database", type=str, help="数据库名") source_group.add_argument("--source-user", type=str, help="用户名") source_group.add_argument("--source-password", type=str, help="密码") @@ -1062,13 +1030,12 @@ def parse_args(): # 目标数据库参数 target_group = parser.add_argument_group("目标数据库配置") target_group.add_argument("--target-path", type=str, help="SQLite 数据库路径") - target_group.add_argument("--target-host", type=str, help="MySQL/PostgreSQL 主机") - target_group.add_argument("--target-port", type=int, help="MySQL/PostgreSQL 端口") + target_group.add_argument("--target-host", type=str, help="PostgreSQL 主机") + target_group.add_argument("--target-port", type=int, help="PostgreSQL 端口") target_group.add_argument("--target-database", type=str, help="数据库名") target_group.add_argument("--target-user", type=str, help="用户名") target_group.add_argument("--target-password", type=str, help="密码") target_group.add_argument("--target-schema", type=str, default="public", help="PostgreSQL schema") - target_group.add_argument("--target-charset", type=str, default="utf8mb4", help="MySQL 字符集") # 跳过表参数 parser.add_argument( @@ -1113,24 +1080,20 @@ def build_config_from_args(args, prefix: str, db_type: str) -> dict | None: return {"path": path} return None - elif db_type in ("mysql", "postgresql"): + elif db_type == "postgresql": host = getattr(args, f"{prefix}_host", None) if not host: return None config = { "host": host, - "port": getattr(args, f"{prefix}_port") or (3306 if db_type == "mysql" else 5432), + "port": getattr(args, f"{prefix}_port") or 5432, "database": getattr(args, f"{prefix}_database") or "maibot", - "user": getattr(args, f"{prefix}_user") or ("root" if db_type == "mysql" else "postgres"), + "user": getattr(args, f"{prefix}_user") or "postgres", "password": getattr(args, f"{prefix}_password") or "", + "schema": getattr(args, f"{prefix}_schema", "public"), } - if db_type == "mysql": - config["charset"] = getattr(args, f"{prefix}_charset", "utf8mb4") - elif db_type == "postgresql": - config["schema"] = getattr(args, f"{prefix}_schema", "public") - return config return None @@ -1201,14 +1164,14 @@ def interactive_setup() -> dict: print("只需回答几个问题,我会帮你构造迁移配置。") print("=" * 60) - db_types = ["sqlite", "mysql", "postgresql"] + db_types = ["sqlite", "postgresql"] # 选择源数据库 source_type = _ask_choice("请选择【源数据库类型】:", db_types, default_index=0) # 选择目标数据库(不能与源相同) while True: - default_idx = 2 if len(db_types) >= 3 else 0 + default_idx = 1 if len(db_types) >= 2 else 0 target_type = _ask_choice("请选择【目标数据库类型】:", db_types, default_index=default_idx) if target_type != source_type: break @@ -1231,8 +1194,8 @@ def interactive_setup() -> dict: source_path = _ask_str("源 SQLite 文件路径", default="data/MaiBot.db") source_config = {"path": source_path} else: - port_default = 3306 if source_type == "mysql" else 5432 - user_default = "root" if source_type == "mysql" else "postgres" + port_default = 5432 + user_default = "postgres" host = _ask_str("源数据库 host", default="localhost") port = _ask_int("源数据库 port", default=port_default) database = _ask_str("源数据库名", default="maibot") @@ -1245,9 +1208,7 @@ def interactive_setup() -> dict: "user": user, "password": password, } - if source_type == "mysql": - source_config["charset"] = _ask_str("源数据库字符集", default="utf8mb4") - elif source_type == "postgresql": + if source_type == "postgresql": source_config["schema"] = _ask_str("源数据库 schema", default="public") # 目标数据库配置(必须显式确认) @@ -1260,8 +1221,8 @@ def interactive_setup() -> dict: ) target_config = {"path": target_path} else: - port_default = 3306 if target_type == "mysql" else 5432 - user_default = "root" if target_type == "mysql" else "postgres" + port_default = 5432 + user_default = "postgres" host = _ask_str("目标数据库 host", default="localhost") port = _ask_int("目标数据库 port", default=port_default) database = _ask_str("目标数据库名", default="maibot") @@ -1275,9 +1236,7 @@ def interactive_setup() -> dict: "user": user, "password": password, } - if target_type == "mysql": - target_config["charset"] = _ask_str("目标数据库字符集", default="utf8mb4") - elif target_type == "postgresql": + if target_type == "postgresql": target_config["schema"] = _ask_str("目标数据库 schema", default="public") print() diff --git a/src/chat/message_manager/batch_database_writer.py b/src/chat/message_manager/batch_database_writer.py index f5b9e1c18..74128d8d9 100644 --- a/src/chat/message_manager/batch_database_writer.py +++ b/src/chat/message_manager/batch_database_writer.py @@ -234,13 +234,6 @@ class BatchDatabaseWriter: stmt = sqlite_insert(ChatStreams).values(stream_id=stream_id, **update_data) stmt = stmt.on_conflict_do_update(index_elements=["stream_id"], set_=update_data) - elif global_config.database.database_type == "mysql": - from sqlalchemy.dialects.mysql import insert as mysql_insert - - stmt = mysql_insert(ChatStreams).values(stream_id=stream_id, **update_data) - stmt = stmt.on_duplicate_key_update( - **{key: value for key, value in update_data.items() if key != "stream_id"} - ) elif global_config.database.database_type == "postgresql": from sqlalchemy.dialects.postgresql import insert as pg_insert @@ -268,13 +261,6 @@ class BatchDatabaseWriter: stmt = sqlite_insert(ChatStreams).values(stream_id=stream_id, **update_data) stmt = stmt.on_conflict_do_update(index_elements=["stream_id"], set_=update_data) - elif global_config.database.database_type == "mysql": - from sqlalchemy.dialects.mysql import insert as mysql_insert - - stmt = mysql_insert(ChatStreams).values(stream_id=stream_id, **update_data) - stmt = stmt.on_duplicate_key_update( - **{key: value for key, value in update_data.items() if key != "stream_id"} - ) elif global_config.database.database_type == "postgresql": from sqlalchemy.dialects.postgresql import insert as pg_insert diff --git a/src/chat/message_receive/chat_stream.py b/src/chat/message_receive/chat_stream.py index 0d647687b..b3d61a331 100644 --- a/src/chat/message_receive/chat_stream.py +++ b/src/chat/message_receive/chat_stream.py @@ -3,7 +3,6 @@ import hashlib import time from rich.traceback import install -from sqlalchemy.dialects.mysql import insert as mysql_insert from sqlalchemy.dialects.postgresql import insert as pg_insert from sqlalchemy.dialects.sqlite import insert as sqlite_insert @@ -665,11 +664,6 @@ class ChatManager: if global_config.database.database_type == "sqlite": stmt = sqlite_insert(ChatStreams).values(stream_id=s_data_dict["stream_id"], **fields_to_save) stmt = stmt.on_conflict_do_update(index_elements=["stream_id"], set_=fields_to_save) - elif global_config.database.database_type == "mysql": - stmt = mysql_insert(ChatStreams).values(stream_id=s_data_dict["stream_id"], **fields_to_save) - stmt = stmt.on_duplicate_key_update( - **{key: value for key, value in fields_to_save.items() if key != "stream_id"} - ) elif global_config.database.database_type == "postgresql": stmt = pg_insert(ChatStreams).values(stream_id=s_data_dict["stream_id"], **fields_to_save) # PostgreSQL 需要使用 constraint 参数或正确的 index_elements diff --git a/src/common/database/core/__init__.py b/src/common/database/core/__init__.py index 2e457f37a..09f7f5c56 100644 --- a/src/common/database/core/__init__.py +++ b/src/common/database/core/__init__.py @@ -9,7 +9,6 @@ 支持的数据库: - SQLite (默认) -- MySQL - PostgreSQL """ diff --git a/src/common/database/core/dialect_adapter.py b/src/common/database/core/dialect_adapter.py index e99eb47ae..09156f230 100644 --- a/src/common/database/core/dialect_adapter.py +++ b/src/common/database/core/dialect_adapter.py @@ -2,7 +2,6 @@ 提供跨数据库兼容性支持,处理不同数据库之间的差异: - SQLite: 轻量级本地数据库 -- MySQL: 高性能关系型数据库 - PostgreSQL: 功能丰富的开源数据库 主要职责: @@ -23,7 +22,6 @@ class DatabaseDialect(Enum): """数据库方言枚举""" SQLITE = "sqlite" - MYSQL = "mysql" POSTGRESQL = "postgresql" @@ -68,20 +66,6 @@ DIALECT_CONFIGS: dict[DatabaseDialect, DialectConfig] = { } }, ), - DatabaseDialect.MYSQL: DialectConfig( - dialect=DatabaseDialect.MYSQL, - ping_query="SELECT 1", - supports_returning=False, # MySQL 8.0.21+ 有限支持 - supports_native_json=True, # MySQL 5.7+ - supports_arrays=False, - requires_length_for_index=True, # MySQL 索引需要指定长度 - default_string_length=255, - isolation_level="READ COMMITTED", - engine_kwargs={ - "pool_pre_ping": True, - "pool_recycle": 3600, - }, - ), DatabaseDialect.POSTGRESQL: DialectConfig( dialect=DatabaseDialect.POSTGRESQL, ping_query="SELECT 1", @@ -113,13 +97,13 @@ class DialectAdapter: """初始化适配器 Args: - db_type: 数据库类型字符串 ("sqlite", "mysql", "postgresql") + db_type: 数据库类型字符串 ("sqlite", "postgresql") """ try: cls._current_dialect = DatabaseDialect(db_type.lower()) cls._config = DIALECT_CONFIGS[cls._current_dialect] except ValueError: - raise ValueError(f"不支持的数据库类型: {db_type},支持的类型: sqlite, mysql, postgresql") + raise ValueError(f"不支持的数据库类型: {db_type},支持的类型: sqlite, postgresql") @classmethod def get_dialect(cls) -> DatabaseDialect: @@ -153,15 +137,10 @@ class DialectAdapter: """ config = cls.get_config() - # MySQL 索引列需要指定长度 - if config.requires_length_for_index and indexed: - return String(max_length) - # SQLite 和 PostgreSQL 可以使用 Text if config.dialect in (DatabaseDialect.SQLITE, DatabaseDialect.POSTGRESQL): return Text() if not indexed else String(max_length) - # MySQL 使用 VARCHAR return String(max_length) @classmethod @@ -189,11 +168,6 @@ class DialectAdapter: """是否为 SQLite""" return cls.get_dialect() == DatabaseDialect.SQLITE - @classmethod - def is_mysql(cls) -> bool: - """是否为 MySQL""" - return cls.get_dialect() == DatabaseDialect.MYSQL - @classmethod def is_postgresql(cls) -> bool: """是否为 PostgreSQL""" @@ -211,7 +185,7 @@ def get_indexed_string_field(max_length: int = 255) -> TypeEngine: 这是一个便捷函数,用于在模型定义中获取适合当前数据库的字符串类型 Args: - max_length: 最大长度(对于 MySQL 是必需的) + max_length: 最大长度 Returns: SQLAlchemy 类型 diff --git a/src/common/database/core/engine.py b/src/common/database/core/engine.py index 064178595..d28f307cb 100644 --- a/src/common/database/core/engine.py +++ b/src/common/database/core/engine.py @@ -4,7 +4,6 @@ 支持的数据库类型: - SQLite: 轻量级本地数据库,使用 aiosqlite 驱动 -- MySQL: 高性能关系型数据库,使用 aiomysql 驱动 - PostgreSQL: 功能丰富的开源数据库,使用 asyncpg 驱动 """ @@ -66,9 +65,7 @@ async def get_engine() -> AsyncEngine: logger.info(f"正在初始化 {db_type.upper()} 数据库引擎...") # 根据数据库类型构建URL和引擎参数 - if db_type == "mysql": - url, engine_kwargs = _build_mysql_config(config) - elif db_type == "postgresql": + if db_type == "postgresql": url, engine_kwargs = _build_postgresql_config(config) else: url, engine_kwargs = _build_sqlite_config(config) @@ -123,55 +120,6 @@ def _build_sqlite_config(config) -> tuple[str, dict]: return url, engine_kwargs -def _build_mysql_config(config) -> tuple[str, dict]: - """构建 MySQL 配置 - - Args: - config: 数据库配置对象 - - Returns: - (url, engine_kwargs) 元组 - """ - encoded_user = quote_plus(config.mysql_user) - encoded_password = quote_plus(config.mysql_password) - - if config.mysql_unix_socket: - # Unix socket连接 - encoded_socket = quote_plus(config.mysql_unix_socket) - url = ( - f"mysql+aiomysql://{encoded_user}:{encoded_password}" - f"@/{config.mysql_database}" - f"?unix_socket={encoded_socket}&charset={config.mysql_charset}" - ) - else: - # TCP连接 - url = ( - f"mysql+aiomysql://{encoded_user}:{encoded_password}" - f"@{config.mysql_host}:{config.mysql_port}/{config.mysql_database}" - f"?charset={config.mysql_charset}" - ) - - engine_kwargs = { - "echo": False, - "future": True, - "pool_size": config.connection_pool_size, - "max_overflow": config.connection_pool_size * 2, - "pool_timeout": config.connection_timeout, - "pool_recycle": 3600, - "pool_pre_ping": True, - "connect_args": { - "autocommit": config.mysql_autocommit, - "charset": config.mysql_charset, - "connect_timeout": config.connection_timeout, - }, - } - - logger.info( - f"MySQL配置: {config.mysql_user}@{config.mysql_host}:{config.mysql_port}/{config.mysql_database}" - ) - return url, engine_kwargs - - def _build_postgresql_config(config) -> tuple[str, dict]: """构建 PostgreSQL 配置 diff --git a/src/common/database/core/migration.py b/src/common/database/core/migration.py index c1408c791..fff355fae 100644 --- a/src/common/database/core/migration.py +++ b/src/common/database/core/migration.py @@ -119,9 +119,6 @@ async def check_and_migrate_database(existing_engine=None): ): # SQLite 将布尔值存储为 0 或 1 default_value = "1" if default_arg else "0" - elif dialect.name == "mysql" and isinstance(default_arg, bool): - # MySQL 也使用 1/0 表示布尔值 - default_value = "1" if default_arg else "0" elif isinstance(default_arg, bool): # PostgreSQL 使用 TRUE/FALSE default_value = "TRUE" if default_arg else "FALSE" diff --git a/src/common/database/core/models.py b/src/common/database/core/models.py index 175173639..6125b4b02 100644 --- a/src/common/database/core/models.py +++ b/src/common/database/core/models.py @@ -5,7 +5,6 @@ 支持的数据库类型: - SQLite: 使用 Text 类型 -- MySQL: 使用 VARCHAR(max_length) 用于索引字段 - PostgreSQL: 使用 Text 类型(PostgreSQL 的 Text 类型性能与 VARCHAR 相当) 所有模型使用统一的类型注解风格: @@ -31,12 +30,11 @@ def get_string_field(max_length=255, **kwargs): 根据数据库类型返回合适的字符串字段类型 对于需要索引的字段: - - MySQL: 必须使用 VARCHAR(max_length),因为索引需要指定长度 - PostgreSQL: 可以使用 Text,但为了兼容性使用 VARCHAR - SQLite: 可以使用 Text,无长度限制 Args: - max_length: 最大长度(对于 MySQL 是必需的) + max_length: 最大长度 **kwargs: 传递给 String/Text 的额外参数 Returns: @@ -47,11 +45,8 @@ def get_string_field(max_length=255, **kwargs): assert global_config is not None db_type = global_config.database.database_type - # MySQL 索引需要指定长度的 VARCHAR - if db_type == "mysql": - return String(max_length, **kwargs) # PostgreSQL 可以使用 Text,但为了跨数据库迁移兼容性,使用 VARCHAR - elif db_type == "postgresql": + if db_type == "postgresql": return String(max_length, **kwargs) # SQLite 使用 Text(无长度限制) else: diff --git a/src/common/database/core/session.py b/src/common/database/core/session.py index 751bb51bf..e3df1a03e 100644 --- a/src/common/database/core/session.py +++ b/src/common/database/core/session.py @@ -4,7 +4,6 @@ 支持的数据库类型: - SQLite: 设置 PRAGMA 参数优化并发 -- MySQL: 无特殊会话设置 - PostgreSQL: 可选设置 schema 搜索路径 """ @@ -79,7 +78,6 @@ async def _apply_session_settings(session: AsyncSession, db_type: str) -> None: schema = global_config.database.postgresql_schema if schema and schema != "public": await session.execute(text(f"SET search_path TO {schema}")) - # MySQL 通常不需要会话级别的特殊设置 except Exception: # 复用连接时设置可能已存在,忽略错误 pass @@ -93,7 +91,6 @@ async def get_db_session() -> AsyncGenerator[AsyncSession, None]: 支持的数据库: - SQLite: 自动设置 busy_timeout 和外键约束 - - MySQL: 直接使用,无特殊设置 - PostgreSQL: 支持自定义 schema 使用示例: @@ -132,7 +129,7 @@ async def get_db_session_direct() -> AsyncGenerator[AsyncSession, None]: - 正常退出时自动提交事务 - 发生异常时自动回滚事务 - 如果用户代码已手动调用 commit/rollback,再次调用是安全的 - - 适用于所有数据库类型(SQLite, MySQL, PostgreSQL) + - 适用于所有数据库类型(SQLite, PostgreSQL) Yields: AsyncSession: SQLAlchemy异步会话对象 diff --git a/src/common/database/optimization/connection_pool.py b/src/common/database/optimization/connection_pool.py index ed7d3e5ef..a00335af3 100644 --- a/src/common/database/optimization/connection_pool.py +++ b/src/common/database/optimization/connection_pool.py @@ -128,7 +128,7 @@ class ConnectionPoolManager: - 正常退出时自动提交事务 - 发生异常时自动回滚事务 - 如果用户代码已手动调用 commit/rollback,再次调用是安全的(空操作) - - 支持所有数据库类型:SQLite、MySQL、PostgreSQL + - 支持所有数据库类型:SQLite、PostgreSQL """ connection_info = None @@ -158,7 +158,7 @@ class ConnectionPoolManager: yield connection_info.session # 🔧 正常退出时提交事务 - # 这对所有数据库(SQLite、MySQL、PostgreSQL)都很重要 + # 这对所有数据库(SQLite、PostgreSQL)都很重要 # 因为 SQLAlchemy 默认使用事务模式,不会自动提交 # 注意:如果用户代码已调用 commit(),这里的 commit() 是安全的空操作 if connection_info and connection_info.session: diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 072356db7..162c9c39a 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -16,26 +16,9 @@ from src.config.config_base import ValidatedConfigBase class DatabaseConfig(ValidatedConfigBase): """数据库配置类""" - database_type: Literal["sqlite", "mysql", "postgresql"] = Field(default="sqlite", description="数据库类型") + database_type: Literal["sqlite", "postgresql"] = Field(default="sqlite", description="数据库类型") sqlite_path: str = Field(default="data/MaiBot.db", description="SQLite数据库文件路径") - # MySQL 配置 - mysql_host: str = Field(default="localhost", description="MySQL服务器地址") - mysql_port: int = Field(default=3306, ge=1, le=65535, description="MySQL服务器端口") - mysql_database: str = Field(default="maibot", description="MySQL数据库名") - mysql_user: str = Field(default="root", description="MySQL用户名") - mysql_password: str = Field(default="", description="MySQL密码") - mysql_charset: str = Field(default="utf8mb4", description="MySQL字符集") - mysql_unix_socket: str = Field(default="", description="MySQL Unix套接字路径") - mysql_ssl_mode: Literal["DISABLED", "PREFERRED", "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY"] = Field( - default="DISABLED", description="SSL模式" - ) - mysql_ssl_ca: str = Field(default="", description="SSL CA证书路径") - mysql_ssl_cert: str = Field(default="", description="SSL客户端证书路径") - mysql_ssl_key: str = Field(default="", description="SSL密钥路径") - mysql_autocommit: bool = Field(default=True, description="自动提交事务") - mysql_sql_mode: str = Field(default="TRADITIONAL", description="SQL模式") - # PostgreSQL 配置 postgresql_host: str = Field(default="localhost", description="PostgreSQL服务器地址") postgresql_port: int = Field(default=5432, ge=1, le=65535, description="PostgreSQL服务器端口") diff --git a/src/plugin_system/utils/dependency_alias.py b/src/plugin_system/utils/dependency_alias.py index a7e478d76..7319f274e 100644 --- a/src/plugin_system/utils/dependency_alias.py +++ b/src/plugin_system/utils/dependency_alias.py @@ -61,7 +61,6 @@ INSTALL_NAME_TO_IMPORT_NAME = { "passlib": "passlib", # 密码哈希库 "bcrypt": "bcrypt", # Bcrypt密码哈希 # ============== 数据库 (Database) ============== - "mysql-connector-python": "mysql.connector", # MySQL官方驱动 "psycopg2-binary": "psycopg2", # PostgreSQL驱动 (二进制) "pymongo": "pymongo", # MongoDB驱动 "redis": "redis", # Redis客户端 diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index eec2fbd60..3593bfe9a 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "7.9.5" +version = "7.9.6" #----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读---- #如果你想要修改配置文件,请递增version的值 @@ -12,30 +12,11 @@ version = "7.9.5" #----以上是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读---- [database]# 数据库配置 -database_type = "sqlite" # 数据库类型,支持 "sqlite"、"mysql" 或 "postgresql" +database_type = "sqlite" # 数据库类型,支持 "sqlite" 或 "postgresql" # SQLite 配置(当 database_type = "sqlite" 时使用) sqlite_path = "data/MaiBot.db" # SQLite数据库文件路径 -# MySQL 配置(当 database_type = "mysql" 时使用) -mysql_host = "localhost" # MySQL服务器地址 -mysql_port = 3306 # MySQL服务器端口 -mysql_database = "maibot" # MySQL数据库名 -mysql_user = "root" # MySQL用户名 -mysql_password = "" # MySQL密码 -mysql_charset = "utf8mb4" # MySQL字符集 -mysql_unix_socket = "" # MySQL Unix套接字路径(可选,用于本地连接,优先于host/port) - -# MySQL SSL 配置 -mysql_ssl_mode = "DISABLED" # SSL模式: DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY -mysql_ssl_ca = "" # SSL CA证书路径 -mysql_ssl_cert = "" # SSL客户端证书路径 -mysql_ssl_key = "" # SSL客户端密钥路径 - -# MySQL 高级配置 -mysql_autocommit = true # 自动提交事务 -mysql_sql_mode = "TRADITIONAL" # SQL模式 - # PostgreSQL 配置(当 database_type = "postgresql" 时使用) postgresql_host = "localhost" # PostgreSQL服务器地址 postgresql_port = 5432 # PostgreSQL服务器端口 @@ -50,7 +31,7 @@ postgresql_ssl_ca = "" # SSL CA证书路径 postgresql_ssl_cert = "" # SSL客户端证书路径 postgresql_ssl_key = "" # SSL客户端密钥路径 -# 连接池配置(MySQL 和 PostgreSQL 有效) +# 连接池配置(PostgreSQL 有效) connection_pool_size = 10 # 连接池大小 connection_timeout = 10 # 连接超时时间(秒)