Skip to content
On this page

Prisma 数据库连接

Prisma 提供了灵活的数据库连接配置选项,支持多种数据库类型和连接方式。本指南将详细介绍如何配置和管理 Prisma 的数据库连接。

数据源配置

基本数据源配置

在 Prisma Schema 中配置数据源:

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

支持的数据库类型

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

// MySQL
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

// SQLite
datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

// SQL Server
datasource db {
  provider = "sqlserver"
  url      = env("DATABASE_URL")
}

// MongoDB (预览功能)
datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

连接字符串格式

PostgreSQL 连接字符串

text
# 基本连接
DATABASE_URL="postgresql://username:password@localhost:5432/mydb"

# 带 SSL 选项的连接
DATABASE_URL="postgresql://username:password@localhost:5432/mydb?sslmode=prefer"

# 带 schema 参数的连接
DATABASE_URL="postgresql://username:password@localhost:5432/mydb?schema=public&connection_limit=20"

# 生产环境连接示例
DATABASE_URL="postgresql://user:pass@aws-us-east-1.c1234567890.us-east-1.rds.amazonaws.com:5432/proddb?sslmode=require"

MySQL 连接字符串

text
# 基本连接
DATABASE_URL="mysql://username:password@localhost:3306/mydb"

# 带额外参数的连接
DATABASE_URL="mysql://username:password@localhost:3306/mydb?connection_limit=20&socket_timeout=60"

# 生产环境连接示例
DATABASE_URL="mysql://user:pass@aws-us-east-1.cluster-1234567890.us-east-1.rds.amazonaws.com:3306/proddb"

SQL Server 连接字符串

text
# 基本连接
DATABASE_URL="sqlserver://localhost:1433;database=mydb;user=username;password=password;encrypt=true"

# 详细配置
DATABASE_URL="sqlserver://server.database.windows.net:1433;database=mydb;user=username@server;password=password;encrypt=true;trustServerCertificate=false;loginTimeout=30;isolationLevel=READ_COMMITTED"

SQLite 连接字符串

prisma
// schema.prisma
datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"           // 相对路径
  // 或
  url      = "file:/home/user/app.db"  // 绝对路径
  // 或
  url      = "file:../shared/db.sql?journal_mode=WAL"  // 带参数
}

环境配置

.env 文件配置

text
# 开发环境
DATABASE_URL="postgresql://localhost:5432/myapp_dev"

# 测试环境
TEST_DATABASE_URL="postgresql://localhost:5432/myapp_test"

# 生产环境
DATABASE_URL="postgresql://prod-server:5432/myapp_prod"

不同环境的连接配置

typescript
// utils/prisma.ts
import { PrismaClient } from '@prisma/client'

let prisma: PrismaClient

declare global {
  var prisma: PrismaClient | undefined
}

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient()
} else {
  if (!global.prisma) {
    global.prisma = new PrismaClient({
      log: ['query', 'info', 'warn', 'error'],
    })
  }
  prisma = global.prisma
}

export default prisma

连接池配置

Prisma Client 连接池

typescript
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
    },
  },
  // 连接池选项
  __internal: {
    // 这些是内部选项,可能会变化
  },
})

数据库 URL 中的连接池参数

text
# PostgreSQL 连接池参数
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb?connection_limit=20&pool_timeout=60"

# MySQL 连接池参数
DATABASE_URL="mysql://user:pass@localhost:3306/mydb?connection_limit=20&socket_timeout=60"

安全连接配置

SSL/TLS 配置

text
# PostgreSQL SSL 连接
DATABASE_URL="postgresql://user:pass@host:5432/db?sslmode=require"

# MySQL SSL 连接
DATABASE_URL="mysql://user:pass@host:3306/db?sslaccept=strict"

使用 SSL 证书

typescript
// 使用自定义 SSL 证书
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL,
      // 某些部署环境可能需要额外的 SSL 配置
    },
  },
})

连接测试

测试数据库连接

typescript
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function testConnection() {
  try {
    // 尝试连接数据库
    await prisma.$connect()
    console.log('数据库连接成功')
    
    // 执行简单查询测试
    await prisma.$queryRaw`SELECT 1`
    console.log('数据库查询测试成功')
  } catch (error) {
    console.error('数据库连接失败:', error)
    process.exit(1)
  } finally {
    await prisma.$disconnect()
  }
}

testConnection()

连接健康检查中间件

typescript
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

// 创建健康检查函数
async function healthCheck() {
  try {
    await prisma.$queryRaw`SELECT 1`
    return { status: 'healthy', timestamp: new Date().toISOString() }
  } catch (error) {
    return { 
      status: 'unhealthy', 
      error: error instanceof Error ? error.message : 'Unknown error',
      timestamp: new Date().toISOString() 
    }
  }
}

// 在应用中使用
app.get('/health', async (req, res) => {
  const status = await healthCheck()
  res.status(status.status === 'healthy' ? 200 : 503).json(status)
})

高可用性配置

读写分离(使用多个数据源)

虽然 Prisma 本身不直接支持读写分离,但可以通过以下方式实现:

typescript
// 创建多个 Prisma 客户端实例
const primaryDb = new PrismaClient({
  datasources: {
    db: { url: process.env.PRIMARY_DATABASE_URL },
  },
})

const replicaDb = new PrismaClient({
  datasources: {
    db: { url: process.env.REPLICA_DATABASE_URL },
  },
})

// 根据查询类型选择数据库
class DatabaseService {
  static async read(query: any) {
    return replicaDb.$queryRaw(query) // 从副本读取
  }
  
  static async write(query: any) {
    return primaryDb.$executeRaw(query) // 写入主数据库
  }
}

连接故障转移

typescript
import { PrismaClient } from '@prisma/client'

class ResilientDatabase {
  private primary: PrismaClient
  private secondary?: PrismaClient
  private isPrimaryHealthy = true
  
  constructor() {
    this.primary = new PrismaClient({
      datasources: { db: { url: process.env.PRIMARY_DB_URL } },
    })
    
    if (process.env.SECONDARY_DB_URL) {
      this.secondary = new PrismaClient({
        datasources: { db: { url: process.env.SECONDARY_DB_URL } },
      })
    }
  }
  
  async executeQuery<T>(query: () => Promise<T>): Promise<T> {
    if (this.isPrimaryHealthy) {
      try {
        return await query()
      } catch (error) {
        console.error('Primary DB failed, switching to secondary:', error)
        this.isPrimaryHealthy = false
        if (this.secondary) {
          return await this.secondary.$transaction(async (tx) => {
            return query.bind(this.secondary!)()
          })
        }
        throw error
      }
    } else {
      if (this.secondary) {
        return await this.secondary.$transaction(async (tx) => {
          return query.bind(this.secondary!)()
        })
      }
      throw new Error('Both primary and secondary databases are unavailable')
    }
  }
}

连接监控和日志

启用查询日志

typescript
const prisma = new PrismaClient({
  log: [
    { level: 'query', emit: 'event' },  // 记录所有查询
    { level: 'info', emit: 'stdout' },  // 信息日志
    { level: 'warn', emit: 'stdout' },  // 警告日志
    { level: 'error', emit: 'stdout' }, // 错误日志
  ],
})

// 监听查询事件
prisma.$on('query', (e) => {
  console.log('Query: ' + e.query)
  console.log('Params: ' + e.params)
  console.log('Duration: ' + e.duration + 'ms')
})

性能监控

typescript
const prisma = new PrismaClient({
  log: [
    {
      emit: 'event',
      level: 'query',
    },
  ],
})

// 查询性能监控
prisma.$on('query', (event) => {
  if (event.duration > 1000) { // 记录超过 1 秒的查询
    console.warn(`Slow query detected: ${event.query}`)
    console.warn(`Duration: ${event.duration}ms`)
  }
})

部署环境配置

Docker 环境

text
# Dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

# 在启动前生成 Prisma 客户端
RUN npx prisma generate

EXPOSE 3000

CMD ["npm", "start"]

Docker Compose 配置

yaml
# docker-compose.yml
version: '3.8'
services:
  db:
    image: postgres:14
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  app:
    build: .
    depends_on:
      - db
    environment:
      DATABASE_URL: "postgresql://myuser:mypassword@db:5432/mydb"
    ports:
      - "3000:3000"

volumes:
  postgres_data:

环境变量最佳实践

typescript
// config/database.ts
interface DatabaseConfig {
  url: string
  directUrl?: string
  shadowDatabaseUrl?: string
}

export function getDatabaseConfig(): DatabaseConfig {
  const config: DatabaseConfig = {
    url: process.env.DATABASE_URL!,
  }
  
  if (process.env.DIRECT_DATABASE_URL) {
    config.directUrl = process.env.DIRECT_DATABASE_URL
  }
  
  if (process.env.SHADOW_DATABASE_URL) {
    config.shadowDatabaseUrl = process.env.SHADOW_DATABASE_URL
  }
  
  return config
}

// 使用配置
const dbConfig = getDatabaseConfig()
const prisma = new PrismaClient({
  datasources: { db: dbConfig },
})

通过正确配置数据库连接,您可以确保应用程序能够可靠、安全地访问数据库,并具备适当的性能和容错能力。