SQL 数据库

在您的 Nuxt 应用程序中访问 SQL 数据库以存储和检索关系数据。

入门

通过在您的 nuxt.config.ts 文件中的 hub 对象中添加 database 属性来在您的 NuxtHub 项目中启用数据库。

nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    database: true
  }
})
此选项将在开发过程中使用 Cloudflare 平台代理,并在您部署项目时自动为您的项目创建一个 Cloudflare D1 数据库。
查看我们的 Drizzle ORM 食谱,通过提供架构和迁移来开始使用数据库。
Nuxt DevTools Database
NuxtHub Admin Database

hubDatabase()

返回 D1 数据库客户端 的服务器可组合项。

const db = hubDatabase()
本文档是对 Cloudflare D1 文档 的一个小小的反映。我们建议您阅读它以了解 D1 数据库的全部潜力。

prepare()

生成稍后使用的预处理语句。

const stmt = db.prepare('SELECT * FROM users WHERE name = "Evan You"')
最佳实践是使用预处理语句,它们是由数据库用来运行 SQL 的预编译对象。这是因为预处理语句可以提高整体执行速度并防止 SQL 注入攻击。

bind()

将参数绑定到预处理语句。

const stmt = db.prepare('SELECT * FROM users WHERE name = ?1')

stmt.bind('Evan You')
? 后跟一个数字 (1-999) 代表一个有序参数。该数字表示调用 .bind(...params) 时参数的位置。
const stmt = db
  .prepare('SELECT * FROM users WHERE name = ?2 AND age = ?1')
  .bind(3, 'Leo Chopin')

all()

将所有行作为对象数组返回,其中每个结果行在 results 属性中表示为一个对象(请参阅 返回值对象)。

const { results } = db.prepare('SELECT name, year FROM frameworks LIMIT 2').all()

console.log(results)
/*
[
  {
     name: "Laravel",
     year: 2011,
  },
   {
     name: "Nuxt",
     year: 2016,
  }
 ]
*/

该方法返回一个包含结果(如果适用)、成功状态和元数据对象的对象。

{
  results: array | null, // [] if empty, or null if it does not apply
  success: boolean, // true if the operation was successful, false otherwise
  meta: {
    duration: number, // duration of the operation in milliseconds
    rows_read: number, // the number of rows read (scanned) by this query
    rows_written: number // the number of rows written by this query
  }
}

first()

返回结果的第一行。它不返回像其他方法那样的元数据。相反,它直接返回对象。

const framework = db.prepare('SELECT * FROM frameworks WHERE year = ?1').bind(2016).first()

console.log(framework)
/*
{
  name: "Nuxt",
  year: 2016,
}
*/

通过将列名称作为参数传递来获取第一行中的特定列。

const total = db.prepare('SELECT COUNT(*) AS total FROM frameworks').first('total')
console.log(total) // 23

raw()

将结果作为数组数组返回,其中每行表示为一个数组。返回类型为数组数组,不包含查询元数据。

const rows = db.prepare('SELECT name, year FROM frameworks LIMIT 2').raw()
console.log(rows);

/*
[
  [ "Laravel", 2011 ],
  [ "Nuxt", 2016 ],
]
*/

默认情况下,结果集中不包括列名称。要将列名称作为结果数组的第一行包含在内,请使用 .raw({ columnNames: true })

const rows = db.prepare('SELECT name, year FROM frameworks LIMIT 2').raw({ columnNames: true })
console.log(rows);

/*
[
  [ "name", "year" ],
  [ "Laravel", 2011 ],
  [ "Nuxt", 2016 ],
]
*/

run()

运行查询(或查询),但不返回结果。相反,run() 只返回指标。这对于 UPDATE、DELETE 或 INSERT 等写入操作非常有用。

const result = db
  .prepare('INSERT INTO frameworks (name, year) VALUES ("?1", ?2)')
  .bind('Nitro', 2022)
  .run()

console.log(result)
/*
{
  success: true
  meta: {
    duration: 62,
  }
}
*/

batch()

在单个对数据库的调用中发送多个 SQL 语句。这可以对性能产生巨大影响,因为它减少了到数据库的网络往返延迟。列表中的每个语句都将依次执行和提交,非并发地,并按相同顺序返回结果。

const [info1, info2] = await db.batch([
  db.prepare('UPDATE frameworks SET version = ?1 WHERE name = ?2').bind(3, 'Nuxt'),
  db.prepare('UPDATE authors SET age = ?1 WHERE username = ?2').bind(32, 'atinux'),
])

info1info2 将包含第一个和第二个查询的结果,类似于 .all() 方法的结果(请参阅 返回值对象)。

console.log(info1)
/*
{
  results: [],
  success: true,
  meta: {
    duration: 62,
    rows_read: 0,
    rows_written: 1
  }
}
*/

返回的对象与 .all() 方法相同。

exec()

直接执行一个或多个查询,无需预处理语句或参数绑定。输入可以是通过 \n 分隔的一个或多个查询。

如果发生错误,将抛出一个包含查询和错误消息的异常,执行将停止,并且不会执行进一步的语句。

const result = await hubDatabase().exec(`CREATE TABLE IF NOT EXISTS frameworks (id INTEGER PRIMARY KEY, name TEXT NOT NULL, year INTEGER NOT NULL DEFAULT 0)`)
console.log(result)
/*
{
  count: 1,
  duration: 23
}
*/
此方法的性能可能较差(预处理语句在某些情况下可以重复使用),更重要的是,它安全性较低。仅将此方法用于维护和一次性任务(例如迁移作业)。输入可以是通过 \n 分隔的一个或多个查询。

数据库迁移

数据库迁移为您的数据库架构提供版本控制。它们跟踪更改,并确保通过增量更新在所有环境中一致的架构演变。

自动应用

当您server/database/migrations/*.sql 中的 SQL 迁移将自动应用时

所有应用的迁移都将在 _hub_migrations 数据库表中进行跟踪。

创建迁移

使用以下命令生成一个新的迁移文件

终端
npx nuxthub database migrations create <name>
迁移名称只能包含字母数字字符和 -(空格将转换为 -)。

迁移文件将在 server/database/migrations/ 中创建。

示例
> npx nuxthub database migrations create create-todos
 Created ./server/database/migrations/0001_create-todos.sql

创建完成后,添加您的 SQL 查询以修改数据库架构。

使用 Drizzle ORM 时,当您运行 npx drizzle-kit generate 时,迁移将自动创建。

检查迁移状态

查看所有环境中的待处理和应用的迁移

终端
# Local environment status
npx nuxthub database migrations list

# Preview environment status
npx nuxthub database migrations list --preview

# Production environment status
npx nuxthub database migrations list --production
示例输出
> npx nuxthub database migrations list --production
 Connected to project atidone.
 Using https://todos.nuxt.dev to retrieve migrations.
 Found 1 migration on atidone...
 ./server/database/migrations/0001_create-todos.sql 10/25/2024, 2:43:32 PM
🕒 ./server/database/migrations/0002_create-users.sql Pending

将迁移标记为已应用

对于具有现有迁移的数据库,通过将它们标记为已应用来阻止 NuxtHub 重新运行它们

终端
# Mark applied in local environment
npx nuxthub database migrations mark-all-applied

# Mark applied in preview environment
npx nuxthub database migrations mark-all-applied --preview

# Mark applied in production environment
npx nuxthub database migrations mark-all-applied --production

从 Drizzle ORM 迁移

由于 NuxtHub 不识别先前应用的 Drizzle ORM 迁移(存储在 __drizzle_migrations 中),它将尝试重新运行 server/database/migrations/*.sql 中的所有迁移。要防止这种情况

  1. 将每个环境中已有的迁移标记为已应用
    终端
    # Local environment
    npx nuxthub database migrations mark-all-applied
    
    # Preview environment
    npx nuxthub database migrations mark-all-applied --preview
    
    # Production environment
    npx nuxthub database migrations mark-all-applied --production
    
  2. 删除 server/plugins/database.ts,因为它不再需要。

就是这样!您可以继续使用 npx drizzle-kit generate 来在更新 Drizzle ORM 架构时生成迁移。