Skip to main content

数据库

数据库

¥Database

Fastify 的生态系统提供了一些用于连接各种数据库引擎的插件。本指南涵盖了在 Fastify 组织内维护 Fastify 插件的引擎。

¥Fastify's ecosystem provides a handful of plugins for connecting to various database engines. This guide covers engines that have Fastify plugins maintained within the Fastify organization.

如果你选择的数据库的插件不存在,你仍然可以使用该数据库,因为 Fastify 与数据库无关。通过遵循本指南中列出的数据库插件示例,可以为缺少的数据库引擎编写插件。

¥If a plugin for your database of choice does not exist you can still use the database as Fastify is database agnostic. By following the examples of the database plugins listed in this guide, a plugin can be written for the missing database engine.

如果你想编写自己的 Fastify 插件,请查看 插件指南

¥If you would like to write your own Fastify plugin please take a look at the plugins guide

MySQL

通过运行 npm i @fastify/mysql 安装插件。

¥Install the plugin by running npm i @fastify/mysql.

用法:

¥Usage:

const fastify = require('fastify')()

fastify.register(require('@fastify/mysql'), {
connectionString: 'mysql://root@localhost/mysql'
})

fastify.get('/user/:id', function(req, reply) {
fastify.mysql.query(
'SELECT id, username, hash, salt FROM users WHERE id=?', [req.params.id],
function onResult (err, result) {
reply.send(err || result)
}
)
})

fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})

Postgres

通过运行 npm i pg @fastify/postgres 安装插件。

¥Install the plugin by running npm i pg @fastify/postgres.

示例:

¥Example:

const fastify = require('fastify')()

fastify.register(require('@fastify/postgres'), {
connectionString: 'postgres://postgres@localhost/postgres'
})

fastify.get('/user/:id', function (req, reply) {
fastify.pg.query(
'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id],
function onResult (err, result) {
reply.send(err || result)
}
)
})

fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})

Redis

通过运行 npm i @fastify/redis 安装插件

¥Install the plugin by running npm i @fastify/redis

用法:

¥Usage:

'use strict'

const fastify = require('fastify')()

fastify.register(require('@fastify/redis'), { host: '127.0.0.1' })
// or
fastify.register(require('@fastify/redis'), { url: 'redis://127.0.0.1', /* other redis options */ })

fastify.get('/foo', function (req, reply) {
const { redis } = fastify
redis.get(req.query.key, (err, val) => {
reply.send(err || val)
})
})

fastify.post('/foo', function (req, reply) {
const { redis } = fastify
redis.set(req.body.key, req.body.value, (err) => {
reply.send(err || { status: 'ok' })
})
})

fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})

默认情况下,当 Fastify 服务器关闭时,@fastify/redis 不会关闭客户端连接。要选择加入此行为,请像这样注册客户端:

¥By default @fastify/redis doesn't close the client connection when Fastify server shuts down. To opt-in to this behavior, register the client like so:

fastify.register(require('@fastify/redis'), {
client: redis,
closeClient: true
})

Mongo

通过运行 npm i @fastify/mongodb 安装插件

¥Install the plugin by running npm i @fastify/mongodb

用法:

¥Usage:

const fastify = require('fastify')()

fastify.register(require('@fastify/mongodb'), {
// force to close the mongodb connection when app stopped
// the default value is false
forceClose: true,

url: 'mongodb://mongo/mydb'
})

fastify.get('/user/:id', async function (req, reply) {
// Or this.mongo.client.db('mydb').collection('users')
const users = this.mongo.db.collection('users')

// if the id is an ObjectId format, you need to create a new ObjectId
const id = this.mongo.ObjectId(req.params.id)
try {
const user = await users.findOne({ id })
return user
} catch (err) {
return err
}
})

fastify.listen({ port: 3000 }, err => {
if (err) throw err
})

LevelDB

通过运行 npm i @fastify/leveldb 安装插件

¥Install the plugin by running npm i @fastify/leveldb

用法:

¥Usage:

const fastify = require('fastify')()

fastify.register(
require('@fastify/leveldb'),
{ name: 'db' }
)

fastify.get('/foo', async function (req, reply) {
const val = await this.level.db.get(req.query.key)
return val
})

fastify.post('/foo', async function (req, reply) {
await this.level.db.put(req.body.key, req.body.value)
return { status: 'ok' }
})

fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})

为数据库编写插件

¥Writing plugin for a database library

我们也可以为数据库编写一个插件(例如 Knex、Prisma 或 TypeORM)。我们将在示例中使用 Knex

¥We could write a plugin for a database library too (e.g. Knex, Prisma, or TypeORM). We will use Knex in our example.

'use strict'

const fp = require('fastify-plugin')
const knex = require('knex')

function knexPlugin(fastify, options, done) {
if(!fastify.knex) {
const knex = knex(options)
fastify.decorate('knex', knex)

fastify.addHook('onClose', (fastify, done) => {
if (fastify.knex === knex) {
fastify.knex.destroy(done)
}
})
}

done()
}

export default fp(knexPlugin, { name: 'fastify-knex-example' })

为数据库引擎编写插件

¥Writing a plugin for a database engine

在此示例中,我们将从头开始创建一个基本的 Fastify MySQL 插件(这是一个精简示例,请在生产中使用官方插件)。

¥In this example, we will create a basic Fastify MySQL plugin from scratch (it is a stripped-down example, please use the official plugin in production).

const fp = require('fastify-plugin')
const mysql = require('mysql2/promise')

function fastifyMysql(fastify, options, done) {
const connection = mysql.createConnection(options)

if (!fastify.mysql) {
fastify.decorate('mysql', connection)
}

fastify.addHook('onClose', (fastify, done) => connection.end().then(done).catch(done))

done()
}

export default fp(fastifyMysql, { name: 'fastify-mysql-example' })

迁移

¥Migrations

数据库模式迁移是数据库管理和开发的一个组成部分。迁移提供了一种可重复且可测试的方法来修改数据库架构并防止数据丢失。

¥Database schema migrations are an integral part of database management and development. Migrations provide a repeatable and testable way to modify a database's schema and prevent data loss.

如指南开头所述,Fastify 与数据库无关,任何 Node.js 数据库迁移工具都可以与其一起使用。我们将给出一个使用 Postgrator 的示例,它支持 Postgres、MySQL、SQL Server 和 SQLite。对于 MongoDB 迁移,请检查 migrate-mongo

¥As stated at the beginning of the guide, Fastify is database agnostic and any Node.js database migration tool can be used with it. We will give an example of using Postgrator which has support for Postgres, MySQL, SQL Server and SQLite. For MongoDB migrations, please check migrate-mongo.

Postgrator

Postgrator 是 Node.js SQL 迁移工具,它使用 SQL 脚本目录来更改数据库模式。迁移文件夹中的每个文件都需要遵循以下模式: [version].[action].[optional-description].sql

¥Postgrator is Node.js SQL migration tool that uses a directory of SQL scripts to alter the database schema. Each file in a migrations folder need to follow the pattern: [version].[action].[optional-description].sql.

版本:必须是递增数字(例如 001 或时间戳)。

¥version: must be an incrementing number (e.g. 001 or a timestamp).

操作:应该是 doundodo 实现版本,undo 将其还原。将其视为其他迁移工具中的 updown

¥action: should be do or undo. do implements the version, undo reverts it. Think about it like up and down in other migration tools.

可选说明描述迁移所做的更改。尽管是可选的,但它应该用于所有迁移,因为它使每个人都更容易知道迁移中进行了哪些更改。

¥optional-description describes which changes migration makes. Although optional, it should be used for all migrations as it makes it easier for everyone to know which changes are made in a migration.

在我们的示例中,我们将进行一次创建 users 表的单一迁移,并且我们将使用 Postgrator 来运行迁移。

¥In our example, we are going to have a single migration that creates a users table and we are going to use Postgrator to run the migration.

运行 npm i pg postgrator 以安装示例所需的依赖。

¥Run npm i pg postgrator to install dependencies needed for the example.

// 001.do.create-users-table.sql
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY NOT NULL,
created_at DATE NOT NULL DEFAULT CURRENT_DATE,
firstName TEXT NOT NULL,
lastName TEXT NOT NULL
);
const pg = require('pg')
const Postgrator = require('postgrator')
const path = require('node:path')

async function migrate() {
const client = new pg.Client({
host: 'localhost',
port: 5432,
database: 'example',
user: 'example',
password: 'example',
});

try {
await client.connect();

const postgrator = new Postgrator({
migrationPattern: path.join(__dirname, '/migrations/*'),
driver: 'pg',
database: 'example',
schemaTable: 'migrations',
currentSchema: 'public', // Postgres and MS SQL Server only
execQuery: (query) => client.query(query),
});

const result = await postgrator.migrate()

if (result.length === 0) {
console.log(
'No migrations run for schema "public". Already at the latest one.'
)
}

console.log('Migration done.')

process.exitCode = 0
} catch(err) {
console.error(err)
process.exitCode = 1
}

await client.end()
}

migrate()