在我的 Node/SQLite/Sequelize 项目中,数据库是这样初始化的:
import db from './db.ts';
import Order from './orders.ts';
import User from './users.ts';
await db.sync({ alter: true, logging: false });
今天在我的生产实例中,出现了以下消息:
SequelizeDatabaseError:SQLITE_ERROR:表 Orders_backup 有 15 列,但提供了 16 个值
我理解该消息,并且我了解到
Orders
中最近添加的列由于某种原因未添加到 Orders_backup
中。
我的问题是:为什么?备份表的结构如何与主表不同步?有没有办法防止这种情况发生?
当您启用
db.sync({ alter: true })
时,Sequelize 将为每个表执行以下操作:
CREATE TABLE IF NOT EXISTS `YourTable_backup`
INSERT INTO `YourTable_backup` ... FROM `YourTable`;
DROP TABLE `YourTable`
CREATE TABLE IF NOT EXISTS `YourTable`
INSERT INTO `YourTable` ... FROM `YourTable_backup`;
如果您将记录器功能传递给同步,您可以自己看到查询:
await db.sync({alter: true, logging: (sql: string) => console.log(sql)});
因此,如果中断这种行为,可能会导致很多问题。例如,在开发中,如果您使用nodemon并在几秒钟内更新代码两次,第一次同步将开始,然后它将在某处中断,然后将开始第二次同步。这可能会导致主表中的数据损坏,或一些剩余的
*_backup
表,通常不应该存在于数据库中。
在生产中,如果由于某种原因您的 CI/CD 将被多次触发,或者有人手动重新启动应用程序两次,而第一次同步尚未完成,则在部署时可能会出现此问题。
同步的更多问题(从上面的日志中可以看出)是,每次同步都会按表两次复制所有数据。因此,当您的数据库增长到数千行时,同步时间将增加到几分钟,这也会增加第二次重新启动的可能性,从而中断数据库并使您的主表或
*_backup
表处于不一致状态。
考虑到这一切,建议避免在生产中使用同步,如sequelize文档中所述:
如上所示,sync({force: true })和sync({alter: true })可以是 破坏性操作。因此,不建议将它们用于 生产级软件。相反,应该进行同步 凭借先进的Migrations理念,借助 续集 CLI。