php Postgresql pg_query():重复键值违反唯一约束

时间:2016-11-14 05:32:59

标签: php postgresql joomla phpunit joomla-framework

我们正在努力重构我们的Framework Postgresql驱动程序以允许进行事务处理。在此过程中,我们引入了一些导致以下错误的问题

pg_query(): duplicate key value violates unique constraint DETAIL: Key (id)=(1) already exists

链接到travis测试,其中包含更多细节 https://travis-ci.org/photodude/database/jobs/175596877

有问题的驱动程序的相关部分在此链接

https://github.com/joomla-framework/database/blob/master/src/Postgresql/PostgresqlDriver.php#L711-L819

有问题的相关测试是

https://github.com/joomla-framework/database/blob/master/Tests/DriverPostgresqlTest.php#L1116-L1163

我知道表序列有点混乱了,但我不知道为什么表序列搞砸了,甚至只是如何修复代码以便测试正常运行。

注意:我认为这种失败与准备好和毫无准备的陈述有关

2 个答案:

答案 0 :(得分:0)

在第519行重新启动序列并截断看起来正常的表,但如果它在回滚事务中运行,则不会发生截断,但序列重启will

    Important: Because sequences are non-transactional, changes made by setval are not undone if the transaction rolls back.

请参阅:

s1=> create table test1 ( id serial primary key, a text not null);
CREATE TABLE
s1=> \d
             List of relations
 Schema |     Name     |   Type   | Owner  
--------+--------------+----------+--------
 public | test1        | table    | albert
 public | test1_id_seq | sequence | albert
(2 rows)

s1=> insert into test1(a) values ('apple');
INSERT 0 1
s1=> select * from test1;
 id |   a   
----+-------
  1 | apple
(1 row)

s1=> select * from test1_id_seq;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 test1_id_seq  |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |      32 | f         | t
(1 row)

s1=> insert into test1(a) values ('bannana');
INSERT 0 1
s1=> select * from test1;
 id |    a    
----+---------
  1 | apple
  2 | bannana
(2 rows)

s1=> insert into test1(a) values ('bannana');
INSERT 0 1
s1=> select * from test1;
 id |    a    
----+---------
  1 | apple
  2 | bannana
  3 | bannana
(3 rows)

s1=> select * from test1_id_seq;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 test1_id_seq  |          3 |           1 |            1 | 9223372036854775807 |         1 |           1 |      30 | f         | t
(1 row)

s1=> begin;
BEGIN
s1=> alter sequence test1_id_seq RESTART WITH 1;
ALTER SEQUENCE
s1=> truncate table test1;
TRUNCATE TABLE
s1=> rollback;
ROLLBACK
s1=> select * from test1_id_seq;
 sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 test1_id_seq  |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | f
(1 row)

s1=> select * from test1;
 id |    a    
----+---------
  1 | apple
  2 | bannana
  3 | bannana
(3 rows)

s1=>

答案 1 :(得分:0)

我们仍然不确定根本原因,但整个问题与单元测试有关。即使只检查了一个失败的测试,也会全局重新启动表序列。我们找到了解决问题的方法,但仍在寻找根本原因。

我们还发现我们需要改进所有驱动程序测试的tearDown()方法。