Skip to content

Next.js 数据库集成 🗄️

🎯 概述

Next.js 支持多种数据库集成方案,包括 Prisma、Drizzle、MongoDB 等,适用于不同的应用场景。

📦 Prisma (推荐)

安装

bash
npm install prisma @prisma/client
npx prisma init

定义模型

prisma
// prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
  createdAt DateTime @default(now())
}

生成客户端

bash
npx prisma generate
npx prisma db push

使用 Prisma

tsx
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma = globalForPrisma.prisma || new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

// app/api/posts/route.ts
import { prisma } from '@/lib/prisma'
import { NextResponse } from 'next/server'

export async function GET() {
  const posts = await prisma.post.findMany({
    include: { author: true }
  })
  return NextResponse.json(posts)
}

export async function POST(request: Request) {
  const { title, content, authorId } = await request.json()
  
  const post = await prisma.post.create({
    data: { title, content, authorId }
  })
  
  return NextResponse.json(post)
}

🚀 MongoDB

安装

bash
npm install mongodb

连接数据库

tsx
// lib/mongodb.ts
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI!
const options = {}

let client: MongoClient
let clientPromise: Promise<MongoClient>

if (process.env.NODE_ENV === 'development') {
  const globalWithMongo = global as typeof globalThis & {
    _mongoClientPromise?: Promise<MongoClient>
  }
  
  if (!globalWithMongo._mongoClientPromise) {
    client = new MongoClient(uri, options)
    globalWithMongo._mongoClientPromise = client.connect()
  }
  clientPromise = globalWithMongo._mongoClientPromise
} else {
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

export default clientPromise

使用 MongoDB

tsx
// app/api/users/route.ts
import clientPromise from '@/lib/mongodb'
import { NextResponse } from 'next/server'

export async function GET() {
  const client = await clientPromise
  const db = client.db('myapp')
  const users = await db.collection('users').find({}).toArray()
  
  return NextResponse.json(users)
}

export async function POST(request: Request) {
  const data = await request.json()
  const client = await clientPromise
  const db = client.db('myapp')
  
  const result = await db.collection('users').insertOne(data)
  
  return NextResponse.json(result)
}

📝 Drizzle ORM

安装

bash
npm install drizzle-orm postgres
npm install -D drizzle-kit

定义模式

tsx
// db/schema.ts
import { pgTable, serial, text, timestamp, boolean } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow()
})

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  published: boolean('published').default(false),
  authorId: serial('author_id').references(() => users.id),
  createdAt: timestamp('created_at').defaultNow()
})

使用 Drizzle

tsx
// lib/db.ts
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import * as schema from '@/db/schema'

const client = postgres(process.env.DATABASE_URL!)
export const db = drizzle(client, { schema })

// app/api/posts/route.ts
import { db } from '@/lib/db'
import { posts } from '@/db/schema'
import { eq } from 'drizzle-orm'

export async function GET() {
  const allPosts = await db.select().from(posts)
  return NextResponse.json(allPosts)
}

export async function POST(request: Request) {
  const data = await request.json()
  const newPost = await db.insert(posts).values(data).returning()
  return NextResponse.json(newPost[0])
}

📚 最佳实践

1. 连接池管理

tsx
// lib/prisma.ts
import { PrismaClient } from '@prisma/client'

const prismaClientSingleton = () => {
  return new PrismaClient({
    log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
  })
}

declare global {
  var prisma: undefined | ReturnType<typeof prismaClientSingleton>
}

const prisma = globalThis.prisma ?? prismaClientSingleton()

export default prisma

if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma

2. 错误处理

tsx
export async function GET() {
  try {
    const posts = await prisma.post.findMany()
    return NextResponse.json(posts)
  } catch (error) {
    console.error('数据库错误:', error)
    return NextResponse.json(
      { error: '获取数据失败' },
      { status: 500 }
    )
  }
}

3. 事务处理

tsx
// Prisma 事务
const result = await prisma.$transaction(async (tx) => {
  const user = await tx.user.create({ data: { email: 'test@example.com' } })
  const post = await tx.post.create({ data: { title: 'Hello', authorId: user.id } })
  return { user, post }
})

🔗 相关资源


下一步:学习 Next.js 国际化 (i18n)