# 数据库系统使用文档 本文档详细介绍了本项目中使用的异步数据库系统,包括其架构设计、使用方法和最佳实践。 ## 系统概述 本项目的数据库系统基于 `aiosqlite` 库构建,提供了异步的 SQLite 数据库访问接口。系统主要特性包括: 1. **异步操作**:完全支持异步/await模式,适配NoneBot2框架 2. **连接池**:内置连接池机制,提高数据库访问性能 3. **参数化查询**:支持安全的参数化查询,防止SQL注入 4. **SQL文件支持**:可以直接执行SQL文件中的脚本 5. **类型支持**:支持 `pathlib.Path` 和 `str` 类型的路径参数 ## 核心类和方法 ### DatabaseManager 类 `DatabaseManager` 是数据库操作的核心类,提供了以下主要方法: #### 初始化 ```python from konabot.common.database import DatabaseManager from pathlib import Path # 使用默认数据库路径 db = DatabaseManager() # 指定了义数据库路径 db = DatabaseManager("./data/myapp.db") db = DatabaseManager(Path("./data/myapp.db")) ``` #### 查询操作 ```python # 执行查询语句并返回结果 results = await db.query("SELECT * FROM users WHERE age > ?", (18,)) # 从SQL文件执行查询 results = await db.query_by_sql_file("./sql/get_users.sql", (18,)) ``` #### 执行操作 ```python # 执行非查询语句 await db.execute("INSERT INTO users (name, email) VALUES (?, ?)", ("张三", "zhangsan@example.com")) # 执行SQL脚本(不带参数) await db.execute_script(""" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE ); INSERT INTO users (name, email) VALUES ('测试用户', 'test@example.com'); """) # 从SQL文件执行非查询语句 await db.execute_by_sql_file("./sql/create_tables.sql") # 带参数执行SQL文件 await db.execute_by_sql_file("./sql/insert_user.sql", ("张三", "zhangsan@example.com")) # 执行多条语句(每条语句使用相同参数) await db.execute_many("INSERT INTO users (name, email) VALUES (?, ?)", [ ("张三", "zhangsan@example.com"), ("李四", "lisi@example.com"), ("王五", "wangwu@example.com") ]) # 从SQL文件执行多条语句(每条语句使用相同参数) await db.execute_many_values_by_sql_file("./sql/batch_insert.sql", [ ("张三", "zhangsan@example.com"), ("李四", "lisi@example.com") ]) ``` ## SQL文件处理机制 ### 单语句SQL文件 ```sql -- insert_user.sql INSERT INTO users (name, email) VALUES (?, ?); ``` ```python # 使用方式 await db.execute_by_sql_file("./sql/insert_user.sql", ("张三", "zhangsan@example.com")) ``` ### 多语句SQL文件 ```sql -- setup.sql CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE ); CREATE TABLE IF NOT EXISTS profiles ( user_id INTEGER, age INTEGER, FOREIGN KEY (user_id) REFERENCES users(id) ); ``` ```python # 使用方式 await db.execute_by_sql_file("./sql/setup.sql") ``` ### 多语句带不同参数的SQL文件 ```sql -- batch_operations.sql INSERT INTO users (name, email) VALUES (?, ?); INSERT INTO profiles (user_id, age) VALUES (?, ?); ``` ```python # 使用方式 await db.execute_by_sql_file("./sql/batch_operations.sql", [ ("张三", "zhangsan@example.com"), # 第一条语句的参数 (1, 25) # 第二条语句的参数 ]) ``` ## 最佳实践 ### 1. 数据库表设计 ```sql -- 推荐的表设计实践 CREATE TABLE IF NOT EXISTS example_table ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); ``` ### 2. SQL文件组织 建议按照功能模块组织SQL文件: ``` plugin/ ├── sql/ │ ├── create_tables.sql │ ├── insert_data.sql │ ├── update_data.sql │ └── query_data.sql └── __init__.py ``` ### 3. 错误处理 ```python try: results = await db.query("SELECT * FROM users WHERE id = ?", (user_id,)) except Exception as e: logger.error(f"数据库查询失败: {e}") # 处理错误情况 ``` ### 4. 连接管理 ```python # 在应用启动时初始化 db_manager = DatabaseManager() # 在应用关闭时清理连接 async def shutdown(): await db_manager.close_all_connections() ``` ## 高级特性 ### 连接池配置 ```python class DatabaseManager: def __init__(self, db_path: Optional[Union[str, Path]] = None): # 连接池大小配置 self._pool_size = 5 # 可根据需要调整 ``` ### 事务支持 ```python # 通过execute方法的自动提交机制支持事务 await db.execute("BEGIN TRANSACTION") try: await db.execute("INSERT INTO users (name) VALUES (?)", ("张三",)) await db.execute("INSERT INTO profiles (user_id, age) VALUES (?, ?)", (1, 25)) await db.execute("COMMIT") except Exception: await db.execute("ROLLBACK") raise ``` ## 注意事项 1. **异步环境**:所有数据库操作都必须在异步环境中执行 2. **参数安全**:始终使用参数化查询,避免SQL注入 3. **资源管理**:确保在应用关闭时调用 `close_all_connections()` 4. **SQL解析**:使用 `sqlparse` 库准确解析SQL语句,正确处理包含分号的字符串和注释 5. **错误处理**:适当处理数据库操作可能抛出的异常 ## 常见问题 ### Q: 如何处理数据库约束错误? A: 确保SQL语句中的字段名正确引用,特别是保留字需要使用双引号包围: ```sql CREATE TABLE air_conditioner ( id VARCHAR(128) PRIMARY KEY, "on" BOOLEAN NOT NULL, -- 使用双引号包围保留字 temperature REAL NOT NULL ); ``` ### Q: 如何处理多个语句和参数的匹配? A: 当SQL文件包含多个语句时,参数应该是参数列表,每个语句对应一个参数元组: ```python await db.execute_by_sql_file("./sql/batch.sql", [ ("参数1", "参数2"), # 第一个语句的参数 ("参数3", "参数4") # 第二个语句的参数 ]) ``` 通过遵循这些指南和最佳实践,您可以充分利用本项目的异步数据库系统,构建高性能、安全的数据库应用。