PAYATHON 2026

Symfony 迁移到 PostgreSQL 后如何指定 schema?

数据小陈

结论

如果希望应用默认访问 snb 下的表,应设置 PostgreSQL 连接的 search_path。如果希望 Doctrine 根据实体映射生成带 schema 的表引用,应在 ORM 映射中指定 schema。

SQL 中没有 snb.,不代表查询没有访问 snb。PostgreSQL 会按照 search_path 查找未限定 schema 的表名。PostgreSQL schema 文档

为什么连接字符串中的参数没有达到预期?

Doctrine DBAL 的 PostgreSQL 标准连接参数中,default_table_schema 和 schema 都不是设置默认 schema 的选项。将它们加入 URL,并不意味着 PostgreSQL 会修改 search_path,也不会自动修改 ORM 实体映射。Doctrine DBAL 连接配置

原问题没有提供 Symfony、Doctrine DBAL 和 DoctrineBundle 的版本,因此无法确定这些参数在当前项目中具体如何处理。

方案一:设置应用连接的 search_path

如果所有业务表都位于 snb,可以按登录角色和数据库设置默认搜索路径。按照给出的连接字符串,角色是 postgres,数据库是 apps:

ALTER ROLE postgres IN DATABASE apps
SET search_path TO snb;

请使用有权修改该角色配置的账号执行。如果应用实际使用其他登录角色,将 postgres 替换为对应角色。

该设置只对之后建立的数据库会话生效。执行后需要重新建立应用连接;长期运行的 worker 或持久连接也需要重新连接。PostgreSQL ALTER ROLE 文档

之后可以移除连接字符串中尝试添加的 schema 参数:

DATABASE_URL="postgresql://postgres:*password*@127.0.0.1:5432/apps?serverVersion=18&charset=utf8"

这里保留了原有的 serverVersion=18,实际使用时应确保它与数据库版本相符。

如果应用还需要通过未限定名称访问 public 中的对象,可以根据需要将搜索路径设为 snb, public。当搜索路径中存在同名对象时,顺序会影响最终访问的对象,因此只应加入可信的 schema。

在应用实际使用的连接中验证

通过 Symfony 注入的 Doctrine DBAL Connection 执行以下查询,避免只在另一条管理连接中检查:

SELECT current_database(), current_user, current_schema();
SHOW search_path;

确认当前数据库为 apps、登录角色符合预期,并检查有效的搜索路径。

接着用一张实际存在的业务表测试。下面的 your_table 是占位表名,需要替换:

SELECT * FROM snb.your_table LIMIT 1;
SELECT * FROM your_table LIMIT 1;

如果显式指定 snb 时可以访问,未指定时却提示找不到表,重点检查当前连接的 search_path。如果出现权限错误,则检查 schema 的 USAGE 权限和目标表的访问权限;设置搜索路径本身不会授予权限。PostgreSQL schema 与权限说明

也可以在同一条 Doctrine 连接中临时验证:

$connection->executeStatement('SET search_path TO snb');
$searchPath = $connection->fetchOne('SHOW search_path');

这只影响当前会话。如果通过连接初始化配置,必须覆盖每次新连接和重连,不能只在某个请求中执行一次。

方案二:在 Doctrine 实体映射中指定 schema

如果需要在映射中固定表所属的 schema,可以设置 Table 的 schema。对于支持 PHP Attributes 且已使用这种映射方式的项目,可以在现有实体上配置:

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'your_table', schema: 'snb')]
class YourEntity
{
    // 保留现有主键和字段映射。
}

将 your_table 和 YourEntity 替换为实际表名和实体类名。schema 是 Doctrine ORM 支持的表映射参数;使用其他映射格式的项目,应在对应配置中设置。Doctrine ORM Table 映射文档

这种配置针对 ORM 管理的实体表,不会自动改写手写 SQL。还需要检查关联中间表和显式配置的 sequence 是否仍引用旧的 dbo。

迁移时还要检查什么?

  • 确认 snb 和目标表确实存在。修改连接配置不会自动将原来的表迁移到该 schema。
  • 检查实体映射、原生 SQL 和迁移脚本中是否残留 dbo。显式写出的 dbo.table_name 不会被 search_path 重定向到 snb。
  • 修改映射后,如果项目缓存了 ORM metadata,需要刷新对应缓存,再检查生成的 SQL。
  • 执行数据库迁移前,检查生成的 SQL 是否操作了预期的 schema,尤其注意建表、删表和 sequence 的变化。

备注:内容仅供参考。