【问题标题】:Duplicate ID's being generated violating primary key contraints生成违反主键约束的重复 ID
【发布时间】:2010-11-13 12:51:20
【问题描述】:

谁能帮忙解释一下?我正在使用 Populator 和 Faker gem 将一些生成的数据放入我的数据库中。除其他外,我生成了 10,000 个 cmets(来自“acts_as_commentable”gem。所有这些都有效。但是,当我添加新评论时,我收到一个错误,提示我使用现有 id 违反了主键. 看看下面我的控制台输出。你可以看到我有 10,000 条记录,从 ID 1 开始,以 ID 100000 结束。然后我尝试添加新评论,但它失败了。这只发生在这个模型/表上。我可以添加新用户等

>> Comment.first(:order => 'id').id
=> 1
>> Comment.last(:order => 'id').id
=> 10000
>> Comment.count
=> 10000
>> Comment.create(:title => 'wtf is up?')
ActiveRecord::RecordNotUnique: PGError: ERROR:  duplicate key value violates unique constraint "comments_pkey"
DETAIL:  Key (id)=(1) already exists.

我怀疑这与 Populator gem 如何将记录批处理到数据库中有关。它只发生在我使用 Populator 看到的模型/表格上。

【问题讨论】:

  • 糟糕。标题不好!对于那个很抱歉。不知道那个片段是如何到达那里的。不是很能描述问题,是吗? :)
  • 哦!我也可以编辑标题。固定。

标签: ruby-on-rails postgresql acts-as-commentable


【解决方案1】:

如果 id 列的值在插入语句中显式设置,则会发生这种情况。

对于每个 id-column 在 Postgres 中都有一个序列,通常命名为 tablename_columnname_seq,例如 user_id_seq。

请检查 pgadmin3 中表定义中的名称,因为 rails 不支持具有其他名称的序列。

您可以通过执行类似的操作来修复 ID 过低的序列:

SELECT setval('user_id_seq', 10000);

要学习最高数: SELECT max(id) FROM users;

SELECT max(x) FROM 
   (SELECT max(id) As x FROM users
    UNION SELECT last_value As x FROM user_id_seq As y);

【讨论】:

  • 当很多用户使用数据库时,您不能使用 MAX。许多用户会看到相同的数字,都尝试使用这个数字 +1 并且他们的查询失败:重复键。使用序列或锁定表。
  • 是的,抱歉,我假设他的测试不使用多线程。 SELECT...FOR UPDATE 是使其线程保存的最简单方法,假设使用了事务。
  • 我很确定就是这样。问题是,这是 Populator gem 中的一个问题,所以我不得不停止使用它。但这是有用的信息!
【解决方案2】:

我不知道实际的问题是什么,但肯定与使用 Populator gem 添加记录有关。使用以下方法生成数据:

Populator.sentences(1..3) # makes 3 sentences

很好。

但是,生成类似的记录

User.populate 5000 do |user| # makes 5000 users in batches of 1000
   user.name = Populator.words(1)
   ...
end

里面有什么东西导致了我的问题。请注意,我使用的是 Rails 3.0.1

【讨论】:

    【解决方案3】:

    这是一个方便的 PostreSQL 脚本,可以一次修复所有表的序列

    SELECT  'SELECT SETVAL(' ||quote_literal(quote_ident(S.relname))|| ', MAX(' ||quote_ident(C.attname)|| ') ) FROM ' ||quote_ident(T.relname)|| ';'
    FROM pg_class AS S, pg_depend AS D, pg_class AS T, pg_attribute AS C
    WHERE S.relkind = 'S'
    AND S.oid = D.objid
    AND D.refobjid = T.oid
    AND D.refobjid = C.attrelid
    AND D.refobjsubid = C.attnum
    ORDER BY S.relname;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 2022-01-06
      • 2012-07-15
      • 1970-01-01
      • 2019-05-03
      • 2021-04-11
      • 2016-08-24
      相关资源
      最近更新 更多