一套可以直接用的 PHP 对接国产数据库(达梦 DM8 / 人大金仓 KingbaseES / OceanBase)
  的完整方案。核心思路一句话:能走标准协议就走标准 PDO,语法迁移全部交给数据库自带工具,PHP 这层只做统一封装,绝不自研
  SQL 翻译器。

  ---
  一、选型结论(先看这个,少走弯路)

  ┌─────────────────────┬───────────────────────┬────────────────────────────┬───────┬──────────────────────────────┐
  │       数据库        │       协议本质        │        PHP 最佳驱动        │ 端口  │       自带语法转换工具       │
  ├─────────────────────┼───────────────────────┼────────────────────────────┼───────┼──────────────────────────────┤
  │ OceanBase           │ MySQL 协议(MySQL     │ pdo_mysql(PHP             │ 2881  │ OMS(OceanBase 迁移服务)    │
  │                     │ 模式)                │ 自带,零成本)             │       │                              │
  ├─────────────────────┼───────────────────────┼────────────────────────────┼───────┼──────────────────────────────┤
  │ 人大金仓 KingbaseES │ PostgreSQL 协议       │ pdo_pgsql(PHP 自带)      │ 54321 │ KDTS / KStudio 迁移评估      │
  │  V8                 │                       │                            │       │                              │
  ├─────────────────────┼───────────────────────┼────────────────────────────┼───────┼──────────────────────────────┤
  │ 达梦 DM8            │ 私有协议              │ 官方 pdo_dm 扩展(需编译) │ 5236  │ DTS 数据迁移工具 /           │
  │                     │                       │                            │       │ 兼容模式参数                 │
  └─────────────────────┴───────────────────────┴────────────────────────────┴───────┴──────────────────────────────┘

  大白话:
  - OceanBase 选 MySQL 模式,PHP 当成 MySQL 用,改都不用改。
  - 金仓本质是 PostgreSQL,PHP 当成 PG 用,pdo_pgsql 直接连。
  - 只有达梦是真私有协议,必须装官方扩展,但它给了 PDO 驱动,用法和别的一样。

  ---
  二、安装扩展(一次性)

  # 1) OceanBase(MySQL模式)——PHP 自带,啥都不用装,确认开启即可
  php -m | grep pdo_mysql

  # 2) 人大金仓 ——用 PostgreSQL 扩展,PHP 自带
  php -m | grep pdo_pgsql
  # 没有就装:
  #   Ubuntu:  apt install php-pgsql
  #   CentOS:  yum install php-pgsql

  # 3) 达梦 ——必须编译官方 pdo_dm 扩展
  #   达梦安装目录里自带源码: $DM_HOME/drivers/php_pdo/
  cd $DM_HOME/drivers/php_pdo/pdo_dm
  phpize
  ./configure --with-php-config=/usr/bin/php-config --with-pdo-dm=$DM_HOME
  make && make install
  # 然后在 php.ini 里加一行:
  #   extension=pdo_dm.so
  php -m | grep pdo_dm

  ▎ 为什么达梦要编译? 因为它是私有协议,PHP 官方不带。但达梦把 PDO 驱动源码直接放在安装目录里了,编译一次即可,用法和
  ▎ MySQL 的 PDO 一模一样。

  ---
  三、统一连接层(核心完整代码)

  这一层的作用:上层业务代码只认一个 Db 类,底层换什么国产库都不用改业务。

  <?php
  declare(strict_types=1);

  /**
   * 国产数据库统一连接层
   * 设计原则:只做连接 + PDO 统一封装,不做 SQL 语法翻译(翻译交给数据库自带工具)
   */
  final class Db
  {
      private \PDO $pdo;
      private string $driver;          // 当前驱动类型
      private static array $pool = []; // 简易长连接复用池

      private function __construct(\PDO $pdo, string $driver)
      {
          $this->pdo    = $pdo;
          $this->driver = $driver;
      }

      /**
       * 工厂方法:根据配置创建连接
       * $type: 'oceanbase' | 'kingbase' | 'dm'
       */
      public static function connect(string $type, array $cfg): self
      {
          $key = $type . md5(json_encode($cfg));
          if (isset(self::$pool[$key])) {
              return self::$pool[$key];
          }

          [$dsn, $options] = self::buildDsn($type, $cfg);

          // 所有国产库统一的 PDO 行为,保证一致性
          $options += [
              \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,   // 出错抛异常,别静默
              \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,         // 默认关联数组
              \PDO::ATTR_EMULATE_PREPARES   => false,                     // 用真预处理,防注入+走执行计划
              \PDO::ATTR_PERSISTENT         => true,                      // 长连接,减少握手开销
          ];

          $pdo = new \PDO($dsn, $cfg['user'], $cfg['password'], $options);

          $self = new self($pdo, $type);
          $self->afterConnect();           // 连接后做各库的环境初始化
          self::$pool[$key] = $self;
          return $self;
      }

      /**
       * 关键:不同库的 DSN 拼法(这是唯一需要区分的地方)
       */
      private static function buildDsn(string $type, array $cfg): array
      {
          $host = $cfg['host'];
          $db   = $cfg['database'] ?? '';
          switch ($type) {

              // OceanBase = MySQL 协议,端口默认 2881
              case 'oceanbase':
                  $port = $cfg['port'] ?? 2881;
                  $dsn  = "mysql:host={$host};port={$port};dbname={$db};charset=utf8mb4";
                  return [$dsn, [
                      // MySQL 专属:连接时就设好严格模式,避免脏数据
                      \PDO::MYSQL_ATTR_INIT_COMMAND =>
                          "SET sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'",
                  ]];

              // 人大金仓 = PostgreSQL 协议,端口默认 54321
              case 'kingbase':
                  $port = $cfg['port'] ?? 54321;
                  $dsn  = "pgsql:host={$host};port={$port};dbname={$db}";
                  return [$dsn, []];

              // 达梦 = 私有协议,端口默认 5236
              case 'dm':
                  $port = $cfg['port'] ?? 5236;
                  // 达梦 DSN:dbname 实际指连接库/服务名,host+port 定位实例
                  $dsn  = "dm:host={$host};port={$port}";
                  return [$dsn, []];

              default:
                  throw new \InvalidArgumentException("不支持的数据库类型: {$type}");
          }
      }

      /**
       * 连接后初始化:统一会话环境(时区、编码、模式)
       */
      private function afterConnect(): void
      {
          switch ($this->driver) {
              case 'oceanbase':
                  $this->pdo->exec("SET time_zone = '+08:00'");
                  break;
              case 'kingbase':
                  $this->pdo->exec("SET timezone = 'Asia/Shanghai'");
                  $this->pdo->exec("SET client_encoding = 'UTF8'");
                  break;
              case 'dm':
                  // 达梦设置语句结束符/大小写敏感等会话参数(按需)
                  // 例如统一日期格式,方便和 Oracle 习惯对齐
                  $this->pdo->exec("SET SCHEMA " . ($GLOBALS['__dm_schema'] ?? 'SYSDBA'));
                  break;
          }
      }

      /** 查询:返回多行 */
      public function query(string $sql, array $params = []): array
      {
          $stmt = $this->pdo->prepare($sql);
          $stmt->execute($params);
          return $stmt->fetchAll();
      }

      /** 查询:返回一行 */
      public function first(string $sql, array $params = []): ?array
      {
          $stmt = $this->pdo->prepare($sql);
          $stmt->execute($params);
          $row = $stmt->fetch();
          return $row === false ? null : $row;
      }

      /** 增删改:返回影响行数 */
      public function execute(string $sql, array $params = []): int
      {
          $stmt = $this->pdo->prepare($sql);
          $stmt->execute($params);
          return $stmt->rowCount();
      }

      /** 取最后插入ID(注意:金仓/达梦需配合序列,见下方说明) */
      public function lastId(?string $seq = null): string
      {
          return $this->pdo->lastInsertId($seq);
      }

      /** 事务封装:传一个闭包进来,自动提交/回滚 */
      public function transaction(callable $fn)
      {
          $this->pdo->beginTransaction();
          try {
              $result = $fn($this);
              $this->pdo->commit();
              return $result;
          } catch (\Throwable $e) {
              $this->pdo->rollBack();
              throw $e;
          }
      }

      public function raw(): \PDO { return $this->pdo; }
  }

  大白话解释这段代码:
  - buildDsn() 是唯一需要区分三种库的地方,区别只有“DSN字符串怎么拼”,其余完全统一。
  - ATTR_EMULATE_PREPARES => false 很关键:用真预处理,既防 SQL 注入,又能让国产库走到正确的执行计划(调优基础)。
  - ATTR_PERSISTENT => true 开长连接,国产库建连握手比 MySQL 重,复用连接能省一大笔开销。
  - 业务层永远只调 query / execute / transaction,底层换库不用动业务。

  ---
  四、三种库的使用示例(业务代码长一个样)

  <?php
  // ---- OceanBase ----
  $ob = Db::connect('oceanbase', [
      'host' => '127.0.0.1', 'port' => 2881,
      'database' => 'test', 'user' => 'root@test', 'password' => '****',
  ]);

  // ---- 人大金仓 ----
  $kb = Db::connect('kingbase', [
      'host' => '127.0.0.1', 'port' => 54321,
      'database' => 'test', 'user' => 'system', 'password' => '****',
  ]);

  // ---- 达梦 ----
  $dm = Db::connect('dm', [
      'host' => '127.0.0.1', 'port' => 5236,
      'user' => 'SYSDBA', 'password' => '****',
  ]);

  // 三个库,业务写法完全一样(参数化查询)
  $users = $ob->query("SELECT id, name FROM users WHERE age > ?", [18]);

  $kb->transaction(function (Db $db) {
      $db->execute("UPDATE account SET balance = balance - ? WHERE id = ?", [100, 1]);
      $db->execute("UPDATE account SET balance = balance + ? WHERE id = ?", [100, 2]);
  });

  ▎ 一个必须知道的差异:自增主键 / 拿插入ID
  ▎ - OceanBase(MySQL 模式):AUTO_INCREMENT + lastId() 直接拿。
  ▎ - 金仓 / 达梦:习惯用序列 + 触发器或 IDENTITY 列。拿 ID 时:
  ▎   - 金仓:INSERT ... RETURNING id;lastId('表名_id_seq')- 达梦:SELECT 序列名.CURRVAL; 或建表时用 IDENTITY(1,1)
  ▎
  ▎ 这属于数据库特性差异,不是语法翻译,不要在 PHP 里自己写翻译——建表时统一用IDENTITY 自增列即可抹平。

  ---
  五、语法转换:全部用数据库自带工具(重点,按你的要求)

  核心原则:旧的 MySQL/Oracle SQL 怎么迁过来?不要在 PHP 里写正则替换、不要自研翻译器。每个国产库都有官方工具 +
  兼容模式。

  1. OceanBase ——OMS(迁移服务) + MySQL 模式

  - 建库时选 MySQL 租户模式,DDL/DML 语法和 MySQL 99% 兼容,PHP 代码原样跑。
  - 存量数据/结构迁移用官方 OMS(OceanBase Migration Service):
    - 图形化配置源库(MySQL/Oracle)→目标 OceanBase。
    - 自动做结构转换、全量+增量同步、数据校验,一站式。
  - Oracle 业务迁移则建 Oracle 模式租户,配合 OMS 的 Oracle→OB转换。

  2. 人大金仓 KingbaseES ——兼容模式 + KDTS/KStudio

  - 建库时选 数据库兼容模式(Oracle / MySQL / PG / SQLServer 模式四选一),金仓内核直接吃对应语法。
  - 迁移用官方工具:
    - KStudio / 迁移评估工具:先评估源库 SQL 兼容度,给报告。
    - KDTS(数据迁移工具):自动迁移表结构 + 数据,内置语法转换(Oracle/MySQL →金仓)。
  - 也就是说:你原来的 Oracle SQL,建“Oracle兼容模式”库+ KDTS 迁移,PHP 这层几乎不用改。

  3. 达梦 DM8 ——兼容模式参数 + DTS

  - 实例级兼容参数 COMPATIBLE_MODE(在 dm.ini 配置):
    - 0 达梦原生、1 ... 不同值对应 Oracle / MySQL 等兼容,让达梦直接识别对应方言。
  - 迁移用官方 DTS(DM 数据迁移工具,图形化):
    - 源选 Oracle/MySQL/PG →目标达梦。
    - 自动转换表结构、类型映射、对象(视图/存过/序列),并迁移数据。
  - 大批量数据再用 dmfldr(达梦的快速装载工具,类似 Oracle sqlldr)灌数。

  ▎ 一句话总结这一节: 语法兼容靠“建库时选对兼容模式”,存量迁移靠“O/SKDTS / DTS”这三个官方工具自动转。PHP不碰 SQL
  ▎ 翻译,只负责连接和执行。

  ---
  六、调优体系(连接 + SQL + 库参数三层)

  第 1 层:PHP 连接层调优(已在代码里体现)

  - 长连接 ATTR_PERSISTENT:国产库建连开销大,复用连接收益最大。
  - 真预处理 EMULATE_PREPARES=false:复用执行计划、防注入。
  - 批量写入用一个事务包起来:把 N 条 INSERT 放进 transaction(),避免每条都 commit(这是国产库写入慢的最大元凶)。

  // 批量插入正确姿势:一次事务 + 多值 INSERT
  $dm->transaction(function (Db $db) use ($rows) {
      $sql = "INSERT INTO t_log(uid, action) VALUES " .
             implode(',', array_fill(0, count($rows), '(?,?)'));
      $params = [];
      foreach ($rows as $r) { $params[] = $r['uid']; $params[] = $r['action']; }
      $db->execute($sql, $params);   // 一条语句插一批,最快
  });2 层:SQL 调优(用各库自带分析工具)

  - OceanBase:EXPLAIN 看计划;obclient 里用 SHOW TRACE 看执行链路;对热点表加合适索引,必要时用 outline 绑定计划。
  - 金仓:EXPLAIN (ANALYZE, BUFFERS) SQL;(和 PG 一样);ANALYZE 表名 更新统计信息让优化器选对计划。
  - 达梦:EXPLAIN SELECT ...; 看计划;用自带 DEM/管理工具的“SQL诊断”和DBMS_STATS 收集统计信息。

  第 3 层:数据库参数调优(自带性能视图驱动)

  - OceanBase:调 memory_limit、租户 cpu/mem 配额;看 gv$sql_audit 找慢 SQL。
  - 金仓:调 shared_buffers、work_mem、effective_cache_size(和 PG 一致);看 sys_stat_statements。
  - 达梦:调 BUFFER(数据缓冲区)、MAX_SESSIONS、SORT_BUF_SIZE;用 DEM 控制台看 AWR 类报告找瓶颈。

  ---
  七、整体落地流程(照着做)

  1. 定模式:OceanBase 选 MySQL 模式 / 金仓选对应兼容模式 / 达梦设 COMPATIBLE_MODE。
  2. 装驱动:MySQL、PGSQL 自带;达梦编译 pdo_dm。
  3. 迁数据:OMS / KDTS / DTS 官方工具自动转结构 + 灌数 + 校验。不写翻译代码。
  4. 接 PHP:用上面的 Db 统一类,业务只认 query/execute/transaction。
  5. 调优:连接层(长连接+真预处理+事务批量)→SQL 层(EXPLAIN+统计信息)→参数层(缓冲区+内存)。

  ---
  总结一句大白话: 国产化对接的最优解不是“PHP写得多牛”,而是协议层用标准PDO、迁移层用官方自带工具、PHP
  层薄薄一层统一封装。三种库里只有达梦要编译扩展,其余直接复用 MySQL/PG 驱动;SQL 兼容靠兼容模式,语法转换靠
  OMS/KDTS/DTS,全程零自研翻译器,这就是稳、省、快的方案。

  需要我把某一个库(比如达梦的存储过程调用、或金仓的 RETURNING 取ID)的完整示例再展开吗?

更多推荐