与 PDO 的 DB2 连接在插入或删除时抛出一般错误 -7008

DB2 connection with PDO throws General Error -7008 when Inserting or Deleting

我们正在开发一个 PHP 应用程序,它连接到 PostgreSQL 服务器和带有 DB2 的 IBM i 服务器。虽然与 PGSQL 的 PDO 连接工作得很好,但与 DB2 的连接只能从表中获取;尝试插入或删除会导致以下错误:

SQLSTATE[HY000]: General error: -7008 (SQLExecute[4294960288] at /build/php7.0-ltLrbJ/php7.0-7.0.33/ext/pdo_odbc/odbc_stmt.c:260)

这个错误在我们的开发和生产环境中都会发生。两台服务器都是Ubuntu(版本不同,但相差不大);我正在为 PDO 使用 ODBC 驱动程序。

我们尝试连接到其他 IBM i 服务器和不同的用户,但仍然出现完全相同的问题。可以Select,但不能插入。谷歌搜索错误代码不会产生任何有用的结果,正如您所看到的错误消息本身一样,它是无用的。 SQLExecute中的代码特别没有出现在任何地方,甚至没有一个结果(有一个来自IBM页面的结果,但它实际上是一个不同的错误代码)。

代码非常简单,但可能存在一些明显的错误。

测试脚本:

include("DB2.php");
$oDAO = new DAO();
$res = $oDAO->ejecuta("INSERT INTO <Library>.<File> VALUES (1,0,1)");

DAO:

class DAO{
    var $link;

    public function __construct(){
        // función constructora, inicia la conexión

        $this->link = new PDO("odbc:DRIVER={IBM i Access ODBC Driver};SYSTEM=<System>;PROTOCOL=TCPIP",
                            '<user>', '<pass>');
        $this->link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    }

    private function begin()    { $this->link->beginTransaction(); }
    private function rollback() { $this->link->rollBack(); }
    private function commit()   { $this->link->commit(); }

    public function ejecuta($query){
        try{
            $this->begin();
            $oResult = $this->link->query($query);
            if($oResult){
                $bResult = true;
                $this->commit();
            }else{
                $bResult = false;
                $this->rollback();
            }
        }
        catch (Exception $e){
            echo $e->getMessage();
            $bResult = false;
            $this->rollback();
        }
        return $bResult;
    }
}

坦率地说,我们别无选择,我已经为此浪费了两个星期。我们只需要插入和删除记录。所以欢迎任何帮助。

您描述的症状与尝试在承诺控制下修改数据库一致,但未启用日记功能。

有三种常见的处理方法:

  1. 打开日记功能。这是相当极端的,因为管理数据库的人必须这样做,如果他们关闭了日记功能,很可能他们真的不知道如何处理日记,或者不想这样做。但这是对 i 的 Db2 进行完全承诺控制的唯一实用方法。

  2. 连接自动提交。这将向使用此连接执行的任何 database-modifying SQL 语句添加隐式提交。根据我的经验,这是最常见和最方便的处理方式。

  3. WITH NC 添加到每个相关的 SQL 语句。原则上,这使您可以 statement-by-statement 控制是否暂停承诺控制。实际上,如果您首先考虑这样做,您可能没有启用日记功能,因此您将不得不在每个 database-modifying SQL 语句上执行此操作。这就是为什么大多数人倾向于选项 2 的原因。