以下是针对你提供的 Python 代码编写的 **Markdown 格式技术文档**,适用于项目内部文档或开发者参考手册。 --- # `MySqlor` 类技术文档 ## 概述 `MySqlor` 是一个用于操作 MySQL 数据库的 SQL 构建与元数据提取类,继承自 `SQLor` 基类。它封装了与 MySQL 相关的 DDL 模板、类型映射、分页查询、表结构查询等功能,支持从数据库中提取表、字段、主键、外键、索引等元信息,并提供模型与数据库之间的类型转换机制。 该类主要配合 `pymysql` 驱动使用,通过动态生成 SQL 查询语句实现对数据库结构的反向工程(Reverse Engineering)和 ORM 映射支持。 --- ## 继承关系 ```python class MySqlor(SQLor) ``` - 父类:`SQLor` - 所属模块:`.sor.SQLor` --- ## 导入依赖 ```python from appPublic.argsConvert import ArgsConvert, ConditionConvert from .sor import SQLor from .const import ROWS from .ddl_template_mysql import mysql_ddl_tmpl ``` > - `ArgsConvert`, `ConditionConvert`: 参数与条件转换工具。 > - `ROWS`: 分页常量定义。 > - `mysql_ddl_tmpl`: MySQL 的 DDL 模板(如建表语句模板)。 --- ## 类属性 ### `ddl_template` ```python ddl_template = mysql_ddl_tmpl ``` - 类型:`dict` - 描述:MySQL 的 DDL 建表语句模板,用于根据模型生成建表 SQL。 - 来源:导入自 `ddl_template_mysql.py` 文件中的 `mysql_ddl_tmpl` 变量。 --- ### `db2modelTypeMapping` 将 MySQL 数据库字段类型映射为应用层模型类型(Model Type)。 | 数据库类型 | 模型类型 | |--------------------|--------------| | tinyint | short | | smallint | short | | mediumint | long | | int | long | | bigint | long | | decimal | float | | double | float | | float | float | | char | char | | varchar | str | | tinyblob / tinytext| text | | mediumblob / mediumtext | text | | blob / text | text | | longblob | bin | | longtext | text | | binary / varbinary | text | | date | date | | time | time | | datetime | datetime | | timestamp | datestamp | | year | short | > **说明**: > - BLOB 类型统一映射为 `bin` 或 `text`,取决于大小。 > - 时间类型做了精细化区分,例如 `timestamp` 映射为 `datestamp`,便于后续处理。 --- ### `model2dbTypemapping` 将模型类型映射回数据库字段类型。 | 模型类型 | 数据库类型 | |------------|----------------| | date | date | | time | date | | timestamp | timestamp | | str | varchar | | char | char | | short | int | | long | bigint | | float | double | | text | longtext | | bin | longblob | | file | longblob | > **注意**:`time` 类型在数据库中仍以 `date` 存储,可能需结合上下文解析;实际应考虑使用 `time` 类型优化。 --- ## 类方法 ### `isMe(cls, name)` 判断当前数据库驱动是否匹配。 #### 参数 - `name` (`str`):数据库连接驱动名称(如 `'pymysql'`) #### 返回值 - `bool`:若为 `'pymysql'` 则返回 `True`,否则 `False` #### 示例 ```python if MySqlor.isMe('pymysql'): print("This is MySQL") ``` --- ## 实例方法 ### `grammar(self)` > ⚠️ **当前存在语法错误!** 此方法尝试返回一个包含 `select` 语句模板的字典,但引用了未定义的变量 `select_stmt`。 #### 代码问题 ```python def grammar(self): return { 'select': select_stmt, # ❌ NameError: name 'select_stmt' is not defined } ``` #### 建议修复 应确保 `select_stmt` 已在作用域内定义,或改为字符串形式: ```python def grammar(self): return { 'select': 'SELECT $[fields]$ FROM $[table]$ WHERE $[where]$', } ``` --- ### `placeHolder(self, varname, pos=None)` 返回参数占位符格式(用于预编译 SQL)。 #### 参数 - `varname` (`str`):变量名 - `pos` (`int`, optional):位置参数索引(未使用) #### 返回值 - 若 `varname == '__mainsql__'`,返回空字符串 `''` - 其他情况返回标准占位符 `'%s'`(适配 `pymysql`) #### 用途 用于构建参数化查询,防止 SQL 注入。 #### 示例 ```python cursor.execute(sql, values) # values 将以 %s 替代 ``` --- ### `dataConvert(self, dataList)` 将输入数据标准化为元组格式,供 SQL 执行使用。 #### 参数 - `dataList` (`dict` 或 `list[dict]`):待转换的数据 #### 返回值 - `tuple`:提取出的值组成的元组 #### 行为逻辑 - 如果是字典 → 提取 `.values()` - 如果是字典列表 → 提取每个元素的 `'value'` 字段 - 最终转为 `tuple` #### 示例 ```python data1 = {'a': 1, 'b': 2} # 结果: (1, 2) data2 = [{'value': 1}, {'value': 2}] # 结果: (1, 2) ``` --- ### `pagingSQLmodel(self)` 返回 MySQL 分页查询模板(基于 `LIMIT offset, count`)。 #### 当前代码问题 ```python def pagingSQLmodel(self): return """...""" return """...""" # ❌ 第二个 return 永远不会执行 ``` #### 正确版本(推荐) ```python def pagingSQLmodel(self): return """ SELECT * FROM (%s) A ORDER BY $[sort]$ LIMIT $[from_line]$, $[rows]$ """ ``` #### 占位符说明 | 占位符 | 含义 | |----------------|------------------------| | `%s` | 子查询原始 SQL | | `$[sort]$` | 排序字段(如 `id ASC`)| | `$[from_line]$`| 起始行偏移量(offset) | | `$[rows]$` | 每页记录数(limit) | #### 示例输出 ```sql SELECT * FROM ( SELECT id, name FROM users ) A ORDER BY id DESC LIMIT 10, 20 ``` --- ### `tablesSQL(self)` 生成查询当前数据库所有表名及其注释的 SQL。 #### 返回值 - `str`:查询 `INFORMATION_SCHEMA.TABLES` 的 SQL 语句 #### SQL 内容 ```sql SELECT lower(TABLE_NAME) AS name, lower(TABLE_COMMENT) AS title FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db_name' ``` #### 动态填充 - 使用 `self.dbdesc.get('dbname', 'unknown')` 获取数据库名 #### 输出字段 | 字段 | 说明 | |-------|----------------| | name | 小写表名 | | title | 表注释(小写) | --- ### `fieldsSQL(self, tablename=None)` 查询指定表的所有字段元信息。 #### 参数 - `tablename` (`str`, optional):表名,若不传则查询所有表 #### 返回值 - `str`:查询 `information_schema.columns` 的 SQL #### SQL 片段 ```sql SELECT lower(column_name) AS name, data_type AS type, CASE WHEN character_maximum_length IS NULL THEN NUMERIC_PRECISION ELSE character_maximum_length END AS length, NUMERIC_SCALE AS dec, lower(is_nullable) AS nullable, column_comment AS title, lower(table_name) AS table_name FROM information_schema.columns WHERE lower(TABLE_SCHEMA) = 'your_dbname' AND lower(table_name) = 'your_table' -- 可选 ``` #### 输出字段说明 | 字段 | 说明 | |--------------|----------------------------------| | name | 字段名(小写) | | type | 数据类型 | | length | 长度或精度 | | dec | 小数位数 | | nullable | 是否可为空(yes/no) | | title | 字段注释 | | table_name | 所属表名(小写) | --- ### `fkSQL(self, tablename=None)` 查询外键约束信息。 #### 参数 - `tablename` (`str`, optional):仅查询与该表相关的外键 #### 返回值 - `str`:查询外键关系的 SQL #### SQL 逻辑 联查三张系统表: - `KEY_COLUMN_USAGE` - `TABLES` - `REFERENTIAL_CONSTRAINTS` #### 查询内容 | 字段 | 说明 | |----------------------|--------------------------| | 拥有者 | Schema 名称 | | 父表名称 | 被引用表 | | 父表字段 | 被引用列 | | 子表名称 | 引用表 | | 子表字段 | 引用列 | | 约束名 | 外键约束名称 | | 表注释 | 子表的注释 | | 约束更新规则 | ON UPDATE 规则 | | 约束删除规则 | ON DELETE 规则 | > **过滤条件**:只返回 `REFERENCED_TABLE_NAME IS NOT NULL` 的记录(即真正的外键) --- ### `pkSQL(self, tablename=None)` 查询指定表的主键字段。 #### 参数 - `tablename` (`str`):必须传入表名 #### 返回值 - `str`:查询主键字段的 SQL #### SQL ```sql SELECT DISTINCT column_name AS name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE table_name='your_table' AND constraint_name='PRIMARY' ``` #### 注意事项 - `table_name` 会被强制转为小写 - 使用 `DISTINCT` 避免重复 --- ### `indexesSQL(self, tablename=None)` 查询索引信息(包括唯一索引)。 #### 参数 - `tablename` (`str`, optional):指定表名 #### 返回值 - `str`:获取索引元数据的 SQL #### SQL ```sql SELECT DISTINCT lower(index_name) AS index_name, CASE NON_UNIQUE WHEN 1 THEN 'unique' ELSE '' END AS is_unique, lower(column_name) AS column_name FROM information_schema.statistics WHERE table_schema = 'your_dbname' AND table_name = 'your_table' -- 可选 ``` #### 输出字段 | 字段 | 说明 | |--------------|----------------------------------------| | index_name | 索引名称(小写) | | is_unique | 是否唯一索引(值为 `'unique'` 或空) | | column_name | 索引包含的字段(单个字段一行) | > **注意**:复合索引会拆分为多行显示。 --- ## 使用示例 ```python # 初始化 MySqlor 实例 dbdesc = {'dbname': 'testdb'} mysqlor = MySqlor(dbdesc=dbdesc) # 获取所有表 sql_tables = mysqlor.tablesSQL() print(sql_tables) # 获取某表字段 sql_fields = mysqlor.fieldsSQL('users') print(sql_fields) # 获取主键 sql_pk = mysqlor.pkSQL('users') # 分页模板 paging_model = mysqlor.pagingSQLmodel() final_sql = paging_model % "(SELECT * FROM users)" \ .replace("$[sort]$", "id DESC") \ .replace("$[from_line]$", "0") \ .replace("$[rows]$", "10") ``` --- ## 已知问题与改进建议 | 问题 | 描述 | 建议 | |------|------|------| | `grammar()` 方法报错 | 引用了未定义的 `select_stmt` | 定义常量或抛出 `NotImplementedError` | | `pagingSQLmodel()` 多余返回 | 第二个 `return` 不可达 | 删除无效行 | | `dataConvert()` 缺少健壮性检查 | 对非 dict/list 输入无保护 | 添加类型校验和异常处理 | | `placeHolder` 忽略 `pos` 参数 | 参数未使用 | 可移除或用于未来扩展 | --- ## 总结 `MySqlor` 是一个功能完整的 MySQL 元数据操作类,具备以下能力: ✅ 类型双向映射 ✅ 表/字段/主键/外键/索引信息提取 ✅ 分页 SQL 模板支持 ✅ 参数占位符兼容 `pymysql` ✅ 支持模型驱动开发(MDD / ORM) 建议结合模板引擎(如 Jinja2)进一步提升 SQL 拼接灵活性。 --- > 📝 文档版本:v1.0 > 📅 更新时间:2025-04-05 > © 项目公共组件库团队