You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GCP Spanner Python客户端插入数据时遇重复行事务错误

问题排查与解决

错误原因分析

你遇到的400 Row [...] was already inserted in this transaction错误,主要有两个核心诱因:

  1. 主键冲突:表中已存在对应ID的行(可能是你之前通过UI插入的数据),重复插入时触发主键约束报错。错误信息中的4503837324345344是实际冲突的主键值,说明代码中可能存在参数传递错误,比如时间戳误用导致主键被意外赋值。
  2. 时间戳使用错误:你的表中curr_timestamp列启用了allow_commit_timestamp,这要求使用Spanner专属的提交时间戳机制,而非普通的CURRENT_TIMESTAMP()。误用时间戳写法会引发类型解析错误,进而导致主键列被错误赋值,触发奇怪的重复插入报错。

解决方案

1. 先确认表中已有数据

执行以下查询查看表中已存在的主键:

SELECT Id FROM MyTable;

如果发现代码中要插入的Id=1/Id=2或错误信息中的4503837324345344已存在,可选择删除这些行,或者改用UPSERT(覆盖现有数据)。

2. 修正时间戳的使用方式

针对你的两种插入方法,分别修正代码:

方法1(SQL插入)修正

使用Spanner的PENDING_COMMIT_TIMESTAMP()函数自动填充提交时间,替换原来的CURRENT_TIMESTAMP():

from google.cloud import spanner

spanner_db = instance.database(DATABASE_ID)
insert_query = """INSERT INTO MyTable (Id, name, curr_timestamp) VALUES
(1, 'name1', PENDING_COMMIT_TIMESTAMP()),
(2, 'name2', PENDING_COMMIT_TIMESTAMP())"""

def insert_data(transaction):
    row_ct = transaction.execute_update(insert_query)
    print(f"插入了 {row_ct} 行数据")

spanner_db.run_in_transaction(insert_data)

如果需要覆盖已有数据,把INSERT改成UPSERT即可。

方法2(批量插入)修正

使用spanner.COMMIT_TIMESTAMP常量替代代码中的CURRENT_TIMESTAMP():

from google.cloud import spanner

spanner_db = instance.database(DATABASE_ID)

def insert_batch_data():
    with spanner_db.batch() as batch:
        batch.insert(
            table='MyTable',
            columns=("Id", "name", "curr_timestamp"),
            values=[
                [1, 'name1', spanner.COMMIT_TIMESTAMP],
                [2, 'name2', spanner.COMMIT_TIMESTAMP]
            ]
        )
    print("数据插入完成")

insert_batch_data()

同样,若要覆盖数据,将batch.insert()替换为batch.upsert()。

3. 验证修正效果

执行修正后的代码前,确保:

  • 已导入google.cloud.spanner模块;
  • 表中不存在与插入数据重复的主键;
  • 时间戳写法符合Spanner的allow_commit_timestamp列要求。

内容的提问来源于stack exchange,提问作者Ankit Seth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:00:16