pgsql 非自增id添加报错骚操作

浏览:104 发布日期:2021/05/27 分类:技术分享 关键字: Pgsql 主键
Pgsql 13,PHP8。
主键为uuid。UserModel::create($data);报错:SQLSTATE[25P02]: In failed sql transaction: 7 ERROR: current transaction is aborted, commands ignored until end of transaction block,
是在获取添加记录的主键id时报错。$lastInsId = $this->getLastInsID($query, $sequence);思路:
通过pgsql手册https://www.postgresql.org/docs/13/dml-returning.html得到获取主键的SQL语句是INSERT INTO users (firstname, lastname) VALUES ('Joe', 'Cool') RETURNING id;解决方案:
1. think\db\builder\Pgsql类
$insertSql属性protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';改为protected $insertSql = 'INSERT INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT% RETURNING %PK%';2. 复制think\db\Build类中的insert方法到think\db\builder\Pgsql类里面。添加主键pk到insert语句中。public function insert(Query $query): string
{
    $options = $query->getOptions();

    // 分析并处理数据
    $data = $this->parseData($query, $options['data']);
    if (empty($data)) {
        return '';
    }

    $fields = array_keys($data);
    $values = array_values($data);

    return str_replace(
        ['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%', '%PK%'],
        [
            !empty($options['replace']) ? 'REPLACE' : 'INSERT',
            $this->parseTable($query, $options['table']),
            $this->parseExtra($query, $options['extra']),
            implode(' , ', $fields),
            implode(' , ', $values),
            $this->parseComment($query, $options['comment']),
            $query->getPk()
        ],
        $this->insertSql);
}
3. 复制think\db\PDOConnection类的insert方法和pdoExecute方法到think\db\connector\Pgsql中,并将Pgsql中的pdoExecute方法改为pdoInsertExecute,已视为Pgsql的insert专用执行方法。
更改think\db\connector\Pgsql的pdoInsertExecute方法,让该方法返回 原值(受影响的记录数)和 主键值。protected function pdoInsertExecute(BaseQuery $query, string $sql, array $bind = [], bool $origin = false): array
{
    if ($origin) {
        $query->parseOptions();
    }

    $sth = $this->queryPDOStatement($query->master(true), $sql, $bind);
    $result = $sth->fetch(PDO::FETCH_NUM);
    if (!$origin && !empty($this->config['deploy']) && !empty($this->config['read_master'])) {
        $this->readMaster = true;
    }

    $this->numRows = $this->PDOStatement->rowCount();

    if ($query->getOptions('cache')) {
        // 清理缓存数据
        $cacheItem = $this->parseCache($query, $query->getOptions('cache'));
        $key       = $cacheItem->getKey();
        $tag       = $cacheItem->getTag();

        if (isset($key) && $this->cache->has($key)) {
            $this->cache->delete($key);
        } elseif (!empty($tag) && method_exists($this->cache, 'tag')) {
            $this->cache->tag($tag)->clear();
        }
    }

    return [$this->numRows,$result[0]];
}
更改think\db\connector\Pgsql的insert方法,让其直接从pdoInsertExecute获取主键值public function insert(BaseQuery $query, bool $getLastInsID = false)
{
    // 分析查询表达式
    $options = $query->parseOptions();

    // 生成SQL语句
    $sql = $this->builder->insert($query);
    // 执行操作
    $result = '' == $sql ? 0 : $this->pdoInsertExecute($query, $sql, $query->getBind());
    if ($result[0]) {
        $sequence  = $options['sequence'] ?? null;
        $lastInsId = $result[1];

        $data = $options['data'];

        if ($lastInsId) {
            $pk = $query->getAutoInc();
            if ($pk) {
                $data[$pk] = $lastInsId;
            }
        }

        $query->setOption('data', $data);

        $this->db->trigger('after_insert', $query);

        if ($getLastInsID && $lastInsId) {
            return $lastInsId;
        }
    }

    return $result;
}
调用 $entity = UserModel::create(['username'=>'测试1']);
dump($entity->toArray());


注意:代码没有经过实战,可能有其他bug。
最佳答案
评论( 相关
后面还有条评论,点击查看>>