You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行时能否将HTTP请求重定向至不同服务器?AdonisJS读写分离场景

实现方案

核心结论

完全可以在运行时动态切换数据库请求指向的服务器,无需修改.env文件。.env配置仅在项目启动时加载,运行时修改既不生效也不适合多实例部署场景,你之前排除该方案的判断是正确的。

具体实现步骤

步骤1:预先配置双数据库连接

在config/database.ts中提前配置主库(处理写请求)和读副本(处理读请求)两个连接,参数从.env中提前读取,无需运行时修改:

// config/database.ts 核心配置示例
import { defineConfig } from '@adonisjs/lucid'
import env from '#start/env'

const dbConfig = defineConfig({
  connections: {
    // 主库:处理所有写请求
    mysql_master: {
      client: 'mysql2',
      connection: {
        host: env.get('DB_MASTER_HOST'),
        port: env.get('DB_PORT'),
        user: env.get('DB_USER'),
        password: env.get('DB_PASSWORD'),
        database: env.get('DB_DATABASE'),
      },
      pool: { min: 2, max: 20 },
    },
    // 读副本:处理所有读请求
    mysql_replica: {
      client: 'mysql2',
      connection: {
        host: env.get('DB_REPLICA_HOST'),
        port: env.get('DB_PORT'),
        user: env.get('DB_USER'),
        password: env.get('DB_PASSWORD'),
        database: env.get('DB_DATABASE'),
      },
      pool: { min: 2, max: 20 },
    }
  }
})
export default dbConfig

对应的.env文件提前写入两个数据库的地址即可:

DB_MASTER_HOST=你的主库地址
DB_REPLICA_HOST=你的Amazon Read Replica地址
# 其余共用配置保持正常填写

步骤2:在中间件中动态切换连接

基于你已经实现的请求方法识别逻辑,在中间件中为当前请求绑定对应数据库连接即可:

// app/middleware/db_route_middleware.ts
import type { HttpContext } from '@adonisjs/core/http'
import db from '@adonisjs/lucid/services/db'

export default class DbRouteMiddleware {
  async handle({ request }: HttpContext, next: () => Promise<void>) {
    const readMethodList = ['GET', 'HEAD', 'OPTIONS']
    const isReadRequest = readMethodList.includes(request.method())
    
    // 为当前请求挂载对应连接,后续业务逻辑直接使用request.db操作数据库即可
    request.db = isReadRequest ? db.connection('mysql_replica') : db.connection('mysql_master')
    
    await next()
  }
}

别忘了在start/kernel.ts中注册该全局中间件,对所有请求生效。

步骤3:业务逻辑适配

如果使用原生数据库操作,直接调用上下文中挂载的db实例即可:

// 路由逻辑示例,无需再判断请求方法
router.get('/users', async ({ request }) => {
  return await request.db.from('users').select('*')
})

如果使用Lucid ORM,在查询时指定连接即可:

// 读请求查询示例
const users = await User.query({ connection: 'mysql_replica' }).where('status', 1)
// 写请求操作示例
const newUser = await User.create({ name: '张三' }, { connection: 'mysql_master' })

注意事项

  • 所有事务操作必须统一走主库,Amazon RDS读副本不支持写入和事务提交
  • 对于部分特殊GET接口(如包含日志写入、统计上报逻辑的接口),可在中间件中添加白名单强制走主库
  • 主从同步存在延迟,对数据一致性要求极高的读请求建议直接走主库
  • AdonisJS会自动管理两个连接的连接池,无需额外处理性能问题

内容的提问来源于stack exchange,提问作者PlayHardGoPro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:21:04