Strapi生产环境自定义数据库索引被自动删除的解决方案咨询
系统信息
- Node.js版本: 18.16.0
- NPM版本: 9.5.1
- Strapi版本: 4.10.1
- 数据库: MySQL
- 操作系统: linux/mac os
- 项目语言: Javascript
问题描述
我在src/index.js中通过以下代码为数据库创建自定义索引:
const knex = strapi.db.connection; await knex.schema.alterTable(my_table, async (t) => { t.index(my_columns, my_index); });
创建索引后必须注释掉这段代码,否则服务器重启时会出现重复索引错误。但如果服务器停止数分钟后重启,数据库中所有自定义索引都会被删除。因此每次向生产环境推送新功能时,都需要取消注释代码创建索引,启动服务器后再注释代码重新启动。
我尝试了一个临时解决方案:在服务器每次重启时检查索引是否存在:
const knex = strapi.db.connection; const hasIndex = async (tableName, indexName) => { const [rows] = await knex.raw( `SHOW INDEX FROM \`${tableName}\` WHERE Key_name = '${indexName}'` ); return rows.length > 0; }; if (!(await hasIndex(my_table, my_index))) { await knex.schema.alterTable(my_table, async (t) => { t.index(my_columns, my_index); }); }
但由于每张表都有超过一百万条记录,这种检查并创建索引的方式可能耗时数小时,不适用于生产环境。
请问这是否意味着Strapi不适合生产环境?或者有其他可行的解决方法?
解决方法
Strapi完全适合生产环境,你的问题源于没有使用官方推荐的数据库结构管理方式,以下是可行的解决方案:
1. 通过模型定义添加索引(推荐)
直接在对应模型的配置文件中定义索引,Strapi会自动管理这些索引,不会在重启时丢失,也不会重复创建。
比如在模型的schema.json文件(路径示例:src/api/[content-type]/content-types/[content-type]/schema.json)中添加:
{ "options": { "indexes": [ { "name": "my_custom_index", "columns": ["column1", "column2"], "type": "index" // 如需唯一索引可改为"unique" } ] }, "attributes": { // 你的字段定义 } }
保存后重启Strapi,索引会被自动创建,后续重启服务器也不会被删除。
2. 使用数据库迁移脚本
利用Strapi集成的Knex迁移功能,一次性创建索引,脚本仅执行一次,避免每次启动都操作数据库:
- 生成迁移文件:
npx strapi generate migration create-custom-indexes - 在生成的迁移文件(位于
database/migrations/目录下)中编写代码:exports.up = async (knex) => { await knex.schema.alterTable('my_table', (t) => { t.index(['column1', 'column2'], 'my_custom_index'); }); }; exports.down = async (knex) => { await knex.schema.alterTable('my_table', (t) => { t.dropIndex('my_custom_index'); }); }; - 执行迁移:
npx strapi db:migrate
迁移完成后,后续服务器重启不会再触发该操作,适合大数据量表的索引创建。
3. 关闭自动迁移(按需)
检查生产环境的数据库配置文件config/env/production/database.js,确保autoMigration设置为false:
module.exports = ({ env }) => ({ connection: { // ... 其他配置 settings: { autoMigration: false, }, }, });
关闭自动迁移后,Strapi不会在启动时修改数据库结构,自定义添加的索引不会被删除,但后续模型结构变更需要手动通过迁移脚本处理。
内容的提问来源于stack exchange,提问作者Saksham Jain

