数据库配置
页面摘要:
/config/database定义受支持数据库(如 SQLite、MySQL 和 PostgreSQL)的连接、客户端和连接池。
/config/database.js|ts 文件用于定义用于存储应用程序内容的数据库连接。
Strapi 支持以下数据库: | 数据库 | 推荐 | 最低 | |------------|-------------|---------| | MySQL | 8.4 | 8.0 | | MariaDB | 11.4 | 10.3 | | PostgreSQL | 17.0 | 14.0 | | SQLite | 3 | 3 |
Strapi 不支持 MongoDB(或任何 NoSQL 数据库),也不支持任何"云原生"数据库(如 Amazon Aurora、Google Cloud SQL 等)。
Strapi 应用程序不应连接到非 Strapi 应用程序创建的、或连接到 Strapi v3 数据库的既有数据库。Strapi 团队将不支持此类尝试。尝试连接不受支持的数据库可能会、而且极有可能导致数据丢失。
配置结构
/config/database.js|ts 文件接受 2 个主要配置对象:
connection用于传递给 Knex.js 的数据库配置选项settings用于 Strapi 特定的数据库设置
connection 配置对象
| Parameter | Description | Type | Default |
|---|---|---|---|
client | 用于创建连接的数据库客户端。 |
接受以下值:
sqlite用于 SQLite 数据库postgres用于 PostgreSQL 数据库mysql用于 MySQL 数据库 |String| - | |connection| 数据库连接信息 |Object| - | |debug| 显示数据库交互和错误。 |Boolean|false| |useNullAsDefault
可选,仅用于 SQLite | 使用 NULL 作为默认值 | Boolean | true |
| pool
可选 | 数据库连接池选项 | Object | - |
| acquireConnectionTimeout
可选 | knex 在获取连接时抛出超时错误前等待的时长(毫秒) | Integer | 60000 |
Strapi 仅支持以下 client 值,并在将配置传递给 Knex 之前自动将 client 值重写为以下选项:
client 值 | 实际使用的包 |
|---|---|
| sqlite | better-sqlite3 |
| mysql | mysql2 |
| postgres | pg |
连接参数
connection.connection 对象位于 ./config/database.js(对于 TypeScript 为 ./config/database.ts)中,用于传递数据库连接信息,并接受以下参数:
| Parameter | Description | Type |
|---|---|---|
connectionString | 数据库连接字符串。设置后将覆盖 connection.connection 的其他属性。要禁用请使用空字符串:''。 | |
在 v4.6.2+ 中可用 | String | |
host | 数据库主机名。默认值:localhost。 | String |
port | 数据库端口 | Integer |
database 或 filename | 数据库名称或文件名。 |
- 对于 MySQL 或 PostgreSQL,使用
database键(配合host、port等)。 - 对于 SQLite,仅提供指向数据库文件的
filename。 |String| |user| 用于建立连接的用户名 |String| |password| 用于建立连接的密码 |String| |timezone| 设置本地时间的默认行为。默认值:utc时区选项 |String| |schema| 设置默认数据库 schema。仅用于 Postgres 数据库。 |String| |ssl| 用于 SSL 数据库连接。 使用对象以字符串形式传递证书文件。 |Boolean或Object|
根据所使用的数据库客户端,可以设置更多参数(例如 mysql 的 charset 和 collation)。请查阅数据库客户端文档了解有哪些可用参数,例如 pg、mysql 和 better-sqlite3 的文档。
connection 对象会传递给 Knex。如果 Knex 支持本页未列出的额外选项(例如用于短期凭据的 expirationChecker),你可以在此处添加。
数据库连接池选项
connection.pool 对象(可选)位于 ./config/database.js(对于 TypeScript 为 ./config/database.ts)中,用于传递 Tarn.js 数据库连接池选项,并接受以下参数:
使用 Docker 时,请将连接池的 min 值改为 0,因为 Docker 会终止任何空闲连接,导致无法保持任何到数据库的开放连接(详见 Tarn.js 连接池 设置,由 Knex.js 使用)。
| Parameter | Description | Type | Default |
|---|---|---|---|
min | 保持存活的最小数据库连接数 | Integer | 2 |
max | 保持存活的最大数据库连接数 | Integer | 10 |
acquireTimeoutMillis | 数据库连接尝试超时前的毫秒数 | Integer | 60000 |
createTimeoutMillis | 创建查询尝试超时前的毫秒数 | Integer | 30000 |
destroyTimeoutMillis | 销毁查询尝试超时前的毫秒数 | Integer | 5000 |
idleTimeoutMillis | 空闲数据库连接被销毁前的毫秒数 | Integer | 30000 |
reapIntervalMillis | 检查空闲数据库连接以进行销毁的时间间隔(毫秒) | Integer | 1000 |
createRetryIntervalMillis | 重试失败创建操作前的空闲时间(毫秒) | Integer | 200 |
afterCreate | 连接池获取新连接时执行自定义逻辑的回调函数。 |
详见 Knex.js 文档 | Function | - |
settings 配置对象
settings 对象位于 ./config/database.js(对于 TypeScript 为 ./config/database.ts)中,用于配置 Strapi 特定的数据库设置,并接受以下参数:
| Parameter | Description | Type | Default |
|---|---|---|---|
forceMigration | 允许 schema 同步删除已不再属于内容类型 schema 的表、列、索引和外键。设为 false 可跳过所有删除操作。 | Boolean | true |
runMigrations | 在启动时运行 /database/migrations 中的迁移文件。Strapi 自身的内部迁移和 schema 同步不受此设置影响,都会运行。 | Boolean | true |
useTypescriptMigrations | 在构建目录而非源目录中查找迁移文件,以便执行 TypeScript 迁移。参见使用 TypeScript 代码处理迁移。 | Boolean | false |
尽管名字如此,forceMigration 并不控制迁移是否运行——那是由 runMigrations 控制的。它控制的是 schema 同步是否被允许删除数据库对象。将其设为 false 可防止数据丢失,但 schema 同步仍会将新 schema 记录为参考,因此被跳过的删除操作的表不再被 Strapi 跟踪,如果你之后将该参数设回 true,它也不会被删除。参见数据库迁移。
配置示例
PostgreSQL
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
schema: env('DATABASE_SCHEMA', 'public'), // 非必填
ssl: env.bool('DATABASE_SSL', false) && {
rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false), // 用于自签名证书
},
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
debug: false,
},
});
Strapi 已知存在一个关于服务器 SSL 支持的问题。
为了修复它,你必须将 ssl:{} 对象作为布尔值来禁用它。示例如下:
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
...
ssl: env('DATABASE_SSL', false)
},
},
});
请注意,如果你需要客户端 SSL CA 验证,你需要使用带有 fs 模块的 ssl:{} 对象,将你的 CA 证书转换为字符串。示例如下:
const fs = require('fs');
module.exports = ({ env }) => ({
connection: {
client: 'postgres',
connection: {
...
ssl: {
ca: fs.readFileSync(`${__dirname}/path/to/your/ca-certificate.crt`).toString(),
},
},
},
});
示例:使用 AWS RDS IAM 身份验证的 PostgreSQL(动态密码令牌)
Knex 通过允许你将 connection.connection 提供为函数,并通过 expirationChecker 检查令牌是否需要续期,来支持短期凭据。
import { Signer } from '@aws-sdk/rds-signer';
export default ({ env }) => {
const signer = new Signer({
hostname: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 5432),
username: env('DATABASE_USERNAME', 'strapi'),
});
return {
connection: {
client: 'postgres',
connection: async () => {
const token = await signer.getAuthToken();
const expiresAt = Date.now() + 15 * 60 * 1000;
return {
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: token,
schema: env('DATABASE_SCHEMA', 'public'),
ssl: true,
expirationChecker: () => expiresAt - Date.now() <= 5 * 60 * 1000,
};
},
},
};
};
AWS RDS IAM 身份验证需要 SSL。请参阅 AWS 文档 了解所需的证书包和 SSL 参数。
MySQL/MariaDB
module.exports = ({ env }) => ({
connection: {
client: 'mysql',
connection: {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: {
rejectUnauthorized: env.bool('DATABASE_SSL_SELF', false), // 用于自签名证书
},
},
debug: false,
},
});
SQLite
JavaScript
module.exports = ({ env }) => ({
connection: {
client: 'sqlite',
connection: {
filename: env('DATABASE_FILENAME', '.tmp/data.db'),
},
useNullAsDefault: true,
debug: false,
},
});
Strapi 默认的 SQLite 数据库位于项目根目录的 .tmp/data.db。如果你想自定义路径以将数据库存储在其他位置,请设置 DATABASE_FILENAME 环境变量。
TypeScript
import path from 'path';
export default ({ env }) => ({
connection: {
client: 'sqlite',
connection: {
filename: path.join(
__dirname,
'..',
'..',
env('DATABASE_FILENAME', path.join('.tmp', 'data.db'))
),
},
useNullAsDefault: true,
},
});
数据库中的配置
配置文件不适合多服务器环境。要在生产环境中更新配置,你可以使用数据存储来获取和设置设置。
获取设置
environment(字符串):设置要存储数据的环境。默认是当前环境(如果你的配置与环境无关,可以为空字符串)。type(字符串):设置你的配置是用于api、plugin还是core。默认是core。name(字符串):如果type是api或plugin,必须设置插件或 API 名称。key(字符串,必填):你要存储的键的名称。
// strapi.store(object).get(object);
// 创建可复用的插件 store 变量
const pluginStore = strapi.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'users-permissions',
});
await pluginStore.get({ key: 'grant' });
设置设置
value(任意类型,必填):你要存储的值。
// strapi.store(object).set(object);
// 创建可复用的插件 store 变量
const pluginStore = strapi.store({
environment: strapi.config.environment,
type: 'plugin',
name: 'users-permissions'
});
await pluginStore.set({
key: 'grant',
value: {
...
}
});
动态数据库凭据
某些云提供商会签发在固定时间后过期的短期数据库凭据。例如,AWS RDS IAM 令牌有效期为 15 分钟;GCP Cloud SQL IAM 令牌以类似方式过期;HashiCorp Vault 可以按计划轮换密钥。在 .env 中使用静态密码会在令牌过期后连接池回收空闲连接时导致间歇性的连接失败。
Strapi 通过 Knex 的连接函数模式支持动态凭据。你可以向 connection.connection 传递一个同步或异步函数,而不是普通的连接对象。Knex 在需要打开新的数据库连接时调用此函数,确保连接池始终获得最新凭据。此模式适用于 PostgreSQL 和 MySQL/MariaDB。自 Strapi v5.51.0 起,TypeScript 类型正式接受用于 connection.connection 的同步和异步函数。
在你的函数返回的对象中包含 expirationChecker 属性。Knex 在从连接池复用连接之前调用它;如果返回 true,Knex 会丢弃现有连接并再次调用你的函数以获取最新凭据。
使用 AWS RDS IAM 身份验证的 MySQL/MariaDB
以下示例在连接池每次打开新的 MySQL 连接时,从 AWS SDK 生成一个新的 IAM 身份验证令牌。对于 PostgreSQL 的等价示例,请参阅上文配置示例中的 PostgreSQL + AWS RDS IAM 身份验证示例。
JavaScript
const { Signer } = require('@aws-sdk/rds-signer');
module.exports = ({ env }) => {
const signer = new Signer({
hostname: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 3306),
username: env('DATABASE_USERNAME', 'strapi'),
});
return {
connection: {
client: 'mysql',
connection: async () => {
const token = await signer.getAuthToken();
const expiresAt = Date.now() + 15 * 60 * 1000;
return {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: token,
ssl: true,
expirationChecker: () => expiresAt - Date.now() <= 5 * 60 * 1000,
};
},
},
};
};
TypeScript
import { Signer } from '@aws-sdk/rds-signer';
export default ({ env }) => {
const signer = new Signer({
hostname: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 3306),
username: env('DATABASE_USERNAME', 'strapi'),
});
return {
connection: {
client: 'mysql',
connection: async () => {
const token = await signer.getAuthToken();
const expiresAt = Date.now() + 15 * 60 * 1000;
return {
host: env('DATABASE_HOST', '127.0.0.1'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: token,
ssl: true,
expirationChecker: () => expiresAt - Date.now() <= 5 * 60 * 1000,
};
},
},
};
};
AWS RDS IAM 身份验证需要在 RDS 实例上启用 SSL 和 IAM 数据库身份验证。请参阅 AWS 文档 了解所需的证书包和设置说明。
数据库配置中的环境变量
Strapi v4.6.2 及更高版本将数据库配置选项包含在 ./config/database.js 或 ./config/database.ts 文件中。创建新项目时,会根据你在项目创建期间选择的数据库,将值为 mysql、postgres 或 sqlite 的环境变量 DATABASE_CLIENT 自动添加到 .env 文件中。此外,连接本地开发数据库所需的所有环境变量也会添加到 .env 文件中。以下是生成的配置文件的示例:
JavaScript
const path = require('path');
module.exports = ({ env }) => {
const client = env('DATABASE_CLIENT', 'sqlite');
const connections = {
mysql: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool(
'DATABASE_SSL_REJECT_UNAUTHORIZED',
true
),
},
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
postgres: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool(
'DATABASE_SSL_REJECT_UNAUTHORIZED',
true
),
},
schema: env('DATABASE_SCHEMA', 'public'),
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
sqlite: {
connection: {
filename: path.join(
__dirname,
'..',
env('DATABASE_FILENAME', 'data.db')
),
},
useNullAsDefault: true,
},
};
return {
connection: {
client,
...connections[client],
acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
},
};
};
TypeScript
import path from 'path';
export default ({ env }) => {
const client = env('DATABASE_CLIENT', 'sqlite');
const connections = {
mysql: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool(
'DATABASE_SSL_REJECT_UNAUTHORIZED',
true
),
},
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
postgres: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool(
'DATABASE_SSL_REJECT_UNAUTHORIZED',
true
),
},
schema: env('DATABASE_SCHEMA', 'public'),
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
sqlite: {
connection: {
filename: path.join(
__dirname,
'..',
env('DATABASE_FILENAME', 'data.db')
),
},
useNullAsDefault: true,
},
};
return {
connection: {
client,
...connections[client],
acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
},
};
};
以下是每种可能数据库对应的 .env 文件中数据库相关键的示例:
MySQL or MariaDB
# Database
DATABASE_CLIENT=mysql
DATABASE_HOST=127.0.0.1
DATABASE_PORT=3306
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strap1
DATABASE_SSL=false
PostgreSQL
# Database
DATABASE_CLIENT=postgres
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5432
DATABASE_NAME=strapi
DATABASE_USERNAME=strapi
DATABASE_PASSWORD=strapi
DATABASE_SSL=false
SQLite
# Database
DATABASE_CLIENT=sqlite
DATABASE_FILENAME=.tmp/data.db
v4.6.2 之前版本 Strapi 应用的环境变量
如果你是在 v4.6.2 之前版本开始项目的,可以按照以下流程转换你的 database.js|database.ts 配置文件:
- 将你的应用更新到
v4.6.2或更高版本。参见升级文档。 - 用前面的 JavaScript 或 TypeScript 代码替换你的
./config/database.js或./config/database.ts文件的内容。 - 将前面代码示例中的环境变量添加到你的
.env文件中。 - (可选)添加额外的环境变量,例如
DATABASE_URL和ssl对象的属性。 - 保存更改并重启应用。
不要覆盖以下环境变量:HOST、PORT、APP_KEYS、API_TOKEN_SALT 和 ADMIN_JWT_SECRET。
使用 connectionString 的数据库连接
许多托管的数据库解决方案使用 connectionString 属性将数据库连接到应用。Strapi v4.6.2 及更高版本包含 connectionString 属性。connectionString 是 connection.connection 对象中所有数据库属性的拼接。connectionString:
- 覆盖
connection.connection的其他属性,例如host和port, - 可以通过将属性设为空字符串
''来禁用。
按环境进行数据库管理
Strapi 应用的开发通常包括在本地开发环境(使用本地开发数据库,例如 SQLite)中进行自定义。当应用准备好进入另一个环境(例如生产或预发布)时,应用会部署到不同的数据库实例,通常是 MySQL、MariaDB 或 PostgreSQL。数据库环境变量允许你切换所连接的数据库。要切换数据库连接:
- 对于
MySQL、MariaDB和PostgreSQL,至少设置DATABASE_CLIENT和DATABASE_URL, - 对于
SQLite,至少设置DATABASE_CLIENT和DATABASE_FILENAME。
对于你应用已部署的版本,数据库环境变量应存储在你存储其他密钥的位置。下表给出了数据库环境变量应存储位置的示例:
| Hosting option | 环境变量存储位置 |
|---|---|
| 虚拟私有服务器/虚拟机(例如 AWS EC2) | ecosystem.config.js 或 .env |
| DigitalOcean App Platform | Environment Variables 表 |
| Heroku | Config vars 表 |
数据库安装
Strapi 让你能够选择最适合你项目的数据库。Strapi 支持 PostgreSQL、SQLite 或 MySQL。
SQLite
SQLite 是默认的(参见快速入门指南)也是推荐的数据库,可用于在本地快速创建应用。
在应用创建期间安装 SQLite
使用以下命令之一:
yarn
yarn create strapi-app my-project --quickstart
npm
npx create-strapi-app@latest my-project --quickstart
这将创建一个新项目并在浏览器中启动它。
手动安装 SQLite
在终端中,运行以下命令:
yarn
yarn add better-sqlite3
npm
npm install better-sqlite3
将以下代码添加到你的 /config/database.ts|js 文件:
JavaScript
module.exports = ({ env }) => ({
connection: {
client: 'sqlite',
connection: {
filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '.tmp/data.db')),
},
useNullAsDefault: true,
},
});
TypeScript
import path from 'path';
export default ({ env }) => ({
connection: {
client: 'sqlite',
connection: {
filename: path.join(__dirname, '..', '..', env('DATABASE_FILENAME', '.tmp/data.db')),
},
useNullAsDefault: true,
},
});
PostgreSQL
当将 Strapi 连接到 PostgreSQL 数据库时,数据库用户需要 SCHEMA 权限。虽然数据库管理员默认拥有此权限,但为 Strapi 应用显式创建的新数据库用户则没有。这会导致在尝试加载管理面板控制台时出现 500 错误。
要使用 SCHEMA 权限创建新的 PostgreSQL 用户,请使用以下步骤:
# 使用安全密码创建新的数据库用户
$ CREATE USER my_strapi_db_user WITH PASSWORD 'password';
# 以 PostgreSQL 管理员身份连接到数据库
$ \c my_strapi_db_name admin_user
# 授予用户 schema 权限
$ GRANT ALL ON SCHEMA public TO my_strapi_db_user;