Sequelize 7 的 @sequelize/sqlite3 方言包演进全解:parameterStyle 参数绑定改造、包重命名与 SQLite 适配要点
2026/9/19 15:18:01 网站建设 项目流程

Sequelize 7 的 @sequelize/sqlite3 方言包演进全解:parameterStyle 参数绑定改造、包重命名与 SQLite 适配要点

【免费下载链接】sequelizeFeature-rich ORM for modern Node.js and TypeScript, it supports PostgreSQL (with JSON and JSONB support), MySQL, MariaDB, SQLite, MS SQL Server, Snowflake, Oracle DB, DB2 and DB2 for IBM i.项目地址: https://gitcode.com/gh_mirrors/se/sequelize

本指南以 packages/sqlite3/CHANGELOG.md 为主线,梳理@sequelize/sqlite3方言包从7.0.0-alpha.407.0.0-alpha.48的全部变更,并深入对应源码(dialect.tsquery-generator.jsquery.jsconnection-manager.tsdata-types-overrides.ts)解释每一项变更背后的实现原理。读完本文,你将掌握bindParamparameterStyle的破坏性迁移方式、@sequelize/sqlite@sequelize/sqlite3的包名变化,以及 SQLite 方言在连接管理、数据类型映射、错误处理上的特殊适配。

一、变更总览:alpha.40 到 alpha.48 的版本脉络

@sequelize/sqlite3是 Sequelize v7 的 SQLite 方言连接器,基于sqlite3npm 包实现(见 packages/sqlite3/package.json 的 description 与 dependencies)。其 CHANGELOG 记录了该包在 v7 预发布阶段的主要演进:

版本发布日期类型核心变更
7.0.0-alpha.482026-02-04版本号提升仅随 monorepo 版本号同步,无代码变更
7.0.0-alpha.472025-10-25Features + BREAKING新增参数风格(parameter style);bindParam选项被parameterStyle取代
7.0.0-alpha.462025-03-22版本号提升仅版本号同步
7.0.0-alpha.452025-02-17版本号提升仅版本号同步
7.0.0-alpha.442025-01-27Bug Fixes更新 prettier 至 v3.3.3
7.0.0-alpha.432024-10-04Bug Fixes统一 returning 查询(unify returning queries)
7.0.0-alpha.422024-09-13版本号提升仅版本号同步
7.0.0-alpha.412024-05-17版本号提升仅版本号同步
7.0.0-alpha.402024-04-11Features包重命名:@sequelize/sqlite@sequelize/sqlite3,并禁止冲突选项

可以看出,该包在 alpha 阶段的大量版本(42、45、46、48)只是随 lerna.json 管理的 monorepo 整体发版同步版本号,真正影响使用者的只有四个实质性变更:parameterStyle 改造(alpha.47)、包重命名(alpha.40)、returning 查询统一(alpha.43)以及工具链维护(alpha.44)。下文逐一展开。

二、破坏性变更:bindParamparameterStyle取代(alpha.47)

2.1 变更内容

alpha.47 引入了"参数风格"(parameter style)概念,同时声明了一项破坏性变更:

bindParam选项已被移除,由parameterStyle取代,其默认值为ParameterStyle.BIND

也就是说,旧代码中向查询生成器传入bindParam: true/false来控制"使用绑定参数还是直接内联替换"的写法不再有效。

2.2ParameterStyle枚举定义

新的ParameterStyle枚举定义在 packages/core/src/enums.ts,只有两个成员:

export enum ParameterStyle { /** 参数以绑定参数(bind parameter)的形式加入查询 */ BIND = 'BIND', /** 参数被直接替换进 SQL 字符串 */ REPLACEMENT = 'REPLACEMENT', }
  • BIND:查询语句中的占位符与参数值分离,由驱动在执行时绑定,可避免 SQL 注入,也便于驱动层做语句缓存与类型处理;
  • REPLACEMENT:参数值经转义后直接拼入 SQL 字符串(即传统的替换模式)。

2.3 源码实现:updateQuery中的参数风格分派

在 packages/sqlite3/src/query-generator.js 的updateQuery实现中可以清楚看到这套逻辑:

if ('bindParam' in options) { throw new Error('The bindParam option has been removed. Use parameterStyle instead.'); } // ... const parameterStyle = options?.parameterStyle ?? ParameterStyle.BIND; if (parameterStyle === ParameterStyle.BIND) { bind = pojo(); bindParam = createBindParamGenerator(bind); } // ... 生成 UPDATE 语句,值经 this.escape(value, { ..., bindParam }) 转义 const result = { query }; if (parameterStyle === ParameterStyle.BIND) { result.bind = bind; } return result;

关键细节有三点:

  1. 显式兜底报错:只要 options 中仍出现bindParam键,立即抛出'The bindParam option has been removed. Use parameterStyle instead.',避免旧代码静默失效;
  2. 默认值:未传parameterStyle时按ParameterStyle.BIND处理;
  3. 返回值形态:在BIND模式下,方法返回{ query, bind }bind是由createBindParamGenerator(bind)累积生成的绑定参数对象;在REPLACEMENT模式下只返回{ query }

2.4 命名绑定参数:$前缀

SQLite 方言的绑定参数是命名参数而非位置参数。在 packages/sqlite3/src/dialect.ts 中可以看到:

createBindCollector() { return createNamedParamBindCollector('$'); }

即生成器产生的绑定占位符一律以$开头(如$name$1)。与之呼应,packages/sqlite3/src/query.js 在执行层对参数做了规范化:

  • 若参数是普通对象(命名参数),则对每个键补上$前缀后交给sqlite3驱动;
  • 若参数是数组(位置参数),则逐个元素处理;
  • 同时有一个重要细节:sqlite3驱动目前会忽略 bigint 值,因此源码中通过stringifyIfBigintbigint一律转成字符串再传入(对应 packages/sqlite3/src/query.js)。

2.5 迁移示例

旧的写法(已移除,会抛错):

queryGenerator.updateQuery(tableName, attrValueHash, where, { bindParam: true, });

迁移后的写法:

import { ParameterStyle } from '@sequelize/core'; queryGenerator.updateQuery(tableName, attrValueHash, where, { parameterStyle: ParameterStyle.BIND, // 默认值,也可省略 });

如果需要传统内联替换风格,则显式传入:

queryGenerator.updateQuery(tableName, attrValueHash, where, { parameterStyle: ParameterStyle.REPLACEMENT, });

三、包重命名:@sequelize/sqlite@sequelize/sqlite3(alpha.40)

3.1 变更内容

alpha.40(2024-04-11)完成的 Features 包含两项:

  1. @sequelize/sqlite重命名为@sequelize/sqlite3
  2. 同时禁止冲突选项(ban conflicting options)——即在同一声明中传入相互矛盾、无法同时成立的选项时直接报错,避免歧义配置静默生效。

(该次提交还涉及@sequelize/ibmi命名族的调整,本指南聚焦 SQLite 包本身。)

3.2 当前包信息

重命名后的包以@sequelize/sqlite3为正式名称,见 packages/sqlite3/package.json:

  • 描述:SQLite Connector for Sequelize, based on the sqlite3 npm package;
  • 依赖@sequelize/core@sequelize/utilslodashsqlite3 ^6.0.1
  • 模块格式type: "commonjs",同时通过exports字段提供 ESM/CJS 双入口(import./lib/index.mjsrequire./lib/index.js);
  • 发布配置publishConfig.access: "public",可供公网安装。

3.3 迁移示例

旧包名(已废弃,不再可用):

const { Sequelize } = require('@sequelize/core'); const { SqliteDialect } = require('@sequelize/sqlite');

新包名:

import { Sequelize } from '@sequelize/core'; import { SqliteDialect } from '@sequelize/sqlite3'; const sequelize = new Sequelize({ dialect: SqliteDialect, storage: 'db.sqlite', });

注意:SQLite 方言不支持通过url连接字符串。在 packages/sqlite3/src/dialect.ts 中,parseConnectionUrl直接抛出错误,提示改用storage选项,这也是"禁止冲突选项"精神在连接层的体现。

四、returning 查询统一(alpha.43)

alpha.43(2024-10-04)的 Bug Fixes 为"unify returning queries",统一了各方言RETURNING子句的行为与返回值形态。从 SQLite 方言源码看,这一改动在以下位置落地:

  1. 能力声明:在 packages/sqlite3/src/dialect.ts 中returnValues: 'returning',声明 SQLite 通过RETURNING子句返回写入后的行数据;
  2. 执行方法选择:在 packages/sqlite3/src/query.js 的getDatabaseMethod中,BulkUpdate/Insert/Update/Upsert 查询在开启returning时改用all(取回结果行),否则用run(只拿变更计数);
  3. 响应处理:在_handleQueryResponse(packages/sqlite3/src/query.js)中,insert/update/upsert 场景若returning开启,则把返回列值回填到实例(this.instance.set(...)),并返回受影响行数results.length;未开启时返回metaData.changes

这意味着升级到 alpha.43 之后,SQLite 下saveupdateupsert等操作的返回值语义与其他方言保持一致——写入语句统一支持返回受影响的行。

五、SQLite 方言能力矩阵(从源码看)

SqliteDialect通过AbstractDialect.extendSupport声明了该方言支持/不支持的特性,见 packages/sqlite3/src/dialect.ts。理解这张能力表有助于规避"在其他数据库能用、在 SQLite 上报错"的坑:

能力SQLite 方言状态
DEFAULT VALUES支持
UNION ALL不支持
RIGHT JOIN不支持
returnValues'returning'(用 RETURNING 子句)
INSERTignoreDuplicates' OR IGNORE'
INSERTupdateOnDuplicate' ON CONFLICT DO UPDATE SET'
index:using不支持
index:where/functionBased支持
外键检查可关闭(foreignKeyChecksDisableable支持
约束的add/remove不支持(SQLite 无法直接增删约束)
groupedLimit不支持
数据类型CHAR/DECIMAL不支持
COLLATE_BINARY/CITEXT支持
BIGINT不支持(见下节说明)
JSON支持
jsonOperations / jsonExtraction均关闭
truncate.restartIdentitydelete.limit不支持

另外 packages/sqlite3/src/dialect.ts 声明了最低数据库版本3.8.0,标识符定界符为反引号`,且getDefaultSchema返回空串——SQLite 无 schema 概念。

六、连接配置:storage、mode 与 password

SqliteConnectionOptions定义在 packages/sqlite3/src/connection-manager.ts,共三个连接选项:

6.1storage

数据库文件路径,默认值为当前工作目录下的sequelize.sqlite。两个特殊值:

  • ':memory:':临时内存数据库
  • ''(空字符串):创建临时磁盘数据库

连接管理器使用options.storage ?? path.join(process.cwd(), 'sequelize.sqlite')解析路径,并用??而非||,正是为了让空字符串能正确表达"临时磁盘库"的语义。

重要限制:临时数据库(内存库或空串)要求连接池做如下配置,否则连接会直接抛错(见 packages/sqlite3/src/connection-manager.ts):

  • pool.maxSize必须为1(否则多个连接会各自创建独立的临时库,互相看不见数据);
  • idleTimeoutMillis必须为Infinity(否则空闲连接被回收会导致数据丢失);
  • maxUsesPerResource必须为Infinity
  • 必须关闭读复制(read replication),否则读连接会指向另一个临时库。

6.2mode

打开数据库的模式标志,是一个位组合整数,取值包括OPEN_CREATEOPEN_READONLYOPEN_READWRITEOPEN_SHAREDCACHEOPEN_PRIVATECACHEOPEN_FULLMUTEXOPEN_URI。这些常量由本包直接导出(packages/sqlite3/src/connection-manager.ts)。默认值为OPEN_READWRITE | OPEN_CREATE

import { SqliteDialect, OPEN_CREATE, OPEN_READWRITE } from '@sequelize/sqlite3'; new Sequelize({ dialect: SqliteDialect, storage: 'db.sqlite', mode: OPEN_CREATE | OPEN_READWRITE, });

当以创建模式打开且存储目录不存在时,连接管理器会自动递归创建目录(fs.mkdir(storageDir, { recursive: true }))。

6.3password

用于 SQLite 加密插件(如 SQLCipher)的PRAGMA KEY口令。连接建立后若提供了password,会执行PRAGMA KEY=...(经过sequelize.escape转义)。

6.4 外键与连接生命周期

  • 连接建立后默认执行PRAGMA FOREIGN_KEYS=ON强制启用外键约束;可通过方言选项foreignKeys: false关闭(packages/sqlite3/src/dialect.ts 中SqliteDialectOptions.foreignKeys,默认true)。
  • 方言还支持sqlite3Module选项,可注入兼容sqlite3npm 库 API 的替代实现(官方仅作为最后手段推荐)。
  • validate()通过内部CLOSED_SYMBOL标记判断连接是否已关闭,disconnect()调用驱动close()并置位该标记。

七、数据类型适配:SQLite 的"一切皆存储类"

SQLite 是动态类型数据库,因此 packages/sqlite3/src/_internal/data-types-overrides.ts 将 Sequelize 的强类型模型映射为 SQLite 存储类:

Sequelize 数据类型SQLite 映射说明
BOOLEANINTEGER写入时编码为1/0,读取后仍还原为布尔
STRINGTEXT(binary 时TEXT COLLATE BINARY
CITEXTTEXT COLLATE NOCASE大小写不敏感比较
TINYINT/SMALLINT/MEDIUMINT/INTEGERINTEGER长度(length)选项被忽略并告警
FLOAT/DOUBLE/REALREALSQLite 的 REAL 是 8 字节双精度;FLOAT的单精度语义不受支持,会告警
TIME/DATE/DATEONLY/UUID/ENUMTEXTENUM 目前仅映射为 TEXT,尚无 CHECK 约束校验枚举值
JSONTEXT见下方说明
BLOBBLOB不接受 length

几个值得注意的点:

  • JSON 读写:SQLite 的 JSON 列以 TEXT 存储。JSON.parseDatabaseValue中,若驱动返回的是数字则直接返回,若是字符串则JSON.parse,解析失败抛BaseError(packages/sqlite3/src/_internal/data-types-overrides.ts);
  • BIGINT 限制:方言能力表中BIGINT: false,原因是 sqlite3 驱动会把 bigint 以 JS number 返回而丢失精度(源码注释引用了 TryGhost/node-sqlite3 的 issue),执行层因此会把 bigint 值字符串化后传递;
  • 布尔默认值:查询生成器通过replaceBooleanDefaultsDEFAULT true/false重写为DEFAULT 1/0(packages/sqlite3/src/query-generator.js);
  • 自增主键:创建表时,INTEGER 主键统一输出为INTEGER PRIMARY KEY AUTOINCREMENT(packages/sqlite3/src/query-generator.js),复合主键则收尾追加PRIMARY KEY (...)子句。

八、错误映射:把 SQLite 错误翻译为 Sequelize 语义错误

SqliteQuery.formatError(packages/sqlite3/src/query.js)按驱动错误码做了翻译:

驱动错误码Sequelize 错误类型
SQLITE_CONSTRAINT_UNIQUE/PRIMARYKEY/TRIGGER/FOREIGNKEY/SQLITE_CONSTRAINT(含FOREIGN KEY constraint failedUniqueConstraintError/ForeignKeyConstraintError+ValidationErrorItem列表
SQLITE_BUSYTimeoutError
其他DatabaseError

对于唯一约束冲突,还会同时兼容 SQLite 新旧两版驱动的报错文案(旧版columns x, y are not unique,新版UNIQUE constraint failed: table.x, table.y)来解析冲突字段,并支持模型索引上的自定义msg。另外,insert 查询开启ignoreDuplicates后若返回空结果集,会抛出EmptyResultError提示冲突被忽略(packages/sqlite3/src/query.js)。

九、升级迁移清单

综合以上变更,从旧 alpha 版本升级到@sequelize/sqlite3@7.0.0-alpha.48需要检查以下四点:

  1. 包名:所有@sequelize/sqlite的 import/require 改为@sequelize/sqlite3,方言类名SqliteDialect不变;
  2. 参数绑定:删除所有bindParam传参,按需改用parameterStyle: ParameterStyle.BIND | ParameterStyle.REPLACEMENTBIND为默认值,可省略);若代码路径上仍出现bindParam,会收到明确的报错提示;
  3. returning 语义:写入操作的返回值已统一,依赖受影响行数或返回列的代码请按"insert/update/upsert 支持returning且开启时返回结果行"的新语义核对;
  4. 能力边界:SQLite 不支持RIGHT JOINUNION ALLgroupedLimit、约束add/removeCHAR/DECIMAL/BIGINT等特性,也不支持url连接串;临时数据库(:memory:或空串)必须配合单连接、无限空闲/复用次数的连接池配置,否则建连即报错。

上述每一项都能在 packages/sqlite3/src 目录的源码与 packages/core/src/enums.ts 中得到验证,配合仓库内的 dev 目录与 packages/sqlite3/CHANGELOG.md 可进一步追溯各版本行为。

【免费下载链接】sequelizeFeature-rich ORM for modern Node.js and TypeScript, it supports PostgreSQL (with JSON and JSONB support), MySQL, MariaDB, SQLite, MS SQL Server, Snowflake, Oracle DB, DB2 and DB2 for IBM i.项目地址: https://gitcode.com/gh_mirrors/se/sequelize

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询