最常用轻量用法是直接用Connection执行原生SQL,不走ORM映射;需注入doctrine.dbal.default_connection或显式指定replica_connection;用executeStatement()执行增删改,executeQuery()执行查询并返回Result;参数必须用?占位防注入;动态查询用createQueryBuilder()安全构建;事务必须在同一Connection实例中控制;getParams()获取已解码配置参数。

直接用 Connection 对象执行原生 SQL 查询
最常用、最轻量的用法就是跳过 ORM,直接拿 Connection 执行 SQL。它不走实体映射,适合统计、批量更新、视图查询等场景。
你得先拿到服务实例——Symfony 默认注册了 doctrine.dbal.default_connection(主库),如果配了从库,还有 doctrine.dbal.replica_connection。
- 在控制器或服务里注入
Doctrine\DBAL\Connection类型提示,容器会自动绑定 default 连接 - 若需 replica 连接,必须显式按服务 ID 注入:
#[Autowire(service: 'doctrine.dbal.replica_connection')] -
executeStatement()用于 INSERT/UPDATE/DELETE,返回影响行数;executeQuery()用于 SELECT,返回Result对象 - 参数必须用
?占位符,不能拼字符串,否则有 SQL 注入风险
示例:
$result = $connection->executeQuery('SELECT * FROM countries WHERE population > ?', [1000000000]);
$row = $result->fetchAssociative();
Connection::createQueryBuilder() 构建安全的动态查询
当 WHERE 条件不确定(比如搜索框)、字段要动态拼接时,硬写 SQL 容易出错且难维护。createQueryBuilder() 是 DBAL 提供的轻量级构建器,比 DQL 简单,又比手拼 SQL 安全。
- 它生成的是原生 SQL,不经过 DQL 解析,所以支持任何 MySQL/PostgreSQL 特有语法(如 JSON 函数、窗口函数)
- 所有值都自动转义,WHERE 中的
setParameter()和setParameters()是必须项,漏掉会报错 - 不支持 JOIN 映射或实体关系,只管表名和字段名——你要自己写
FROM users u这样的别名 - 调用
->executeQuery()后仍返回Result,不是实体对象
示例:
$qb = $connection->createQueryBuilder();
$qb->select('*')->from('countries')->where('population > :min')->setParameter('min', 500000000);
$result = $qb->executeQuery();事务控制必须用同一个 Connection 实例
Doctrine 的事务是连接级别的,不是 EntityManager 级别的。哪怕你有两个 EntityManager 都指向同一数据库,它们的 Connection 若不是同一个实例,beginTransaction() 就互不感知。
- 一个请求中若混用
default_connection和replica_connection,事务只能在前者上开启;后者调beginTransaction()会静默失败或抛DriverException - 写后立刻读(如创建订单后查单号),不能先用 default 写、再用 replica 读——replica 可能还没同步,且事务已结束,无法保证一致性
- 手动事务中禁止切换连接:一旦
beginTransaction()被调,后续所有executeStatement()或executeQuery()必须用同一个 Connection 实例 - 如果要用事务,就别碰 replica;如果要用 replica,就确保不在事务上下文里
获取连接参数数组用 getParams(),别解析 DSN 字符串
有时你需要 host、dbname、user 这些原始配置(比如给第三方 SDK 传参),不要自己 parse DATABASE_URL 字符串——特殊字符(@ / :)会导致截断或解码错误。
-
$connection->getParams()返回的是已解析、已解码的关联数组,包含host、port、dbname、user、password、driver等键 - 该方法不触发实际数据库连接,只是读取初始化时缓存的配置
- 如果你注入的是
replica_connection,getParams()返回的就是 replica 的真实参数,不是 default 的 - 注意:
url键可能不存在,因为有些项目用拆解参数方式配置(host+dbname),而不是 DSN
示例:
$params = $connection->getParams(); echo $params['host']; // 输出 replica 的 host,非 default
事务和连接绑定是硬约束,不是建议;replica 连接连 beginTransaction() 都不允许调,这点容易被当成“性能优化可选项”而忽略。


















