据我所知,postgres 中的外键约束违规不应该发生。 (带休眠)

发布于 2024-10-27 21:40:55 字数 1320 浏览 1 评论 0原文

所以我有两个表:

table A
-id
-other stuff

table B
-id
-stuff
-a_id, a fk column to id in A

在 hibernate 中,我将 B.a_id 映射为一个简单的属性(我不需要多对一并获取整个 A 实例,我只想要 Id)。假设 A 中有一行 id=100。

如果我尝试将 a_id=100 的新行插入 B 中,我会收到 postgres 外键约束冲突,指出不存在 id=100 的 A !

我不明白这一点。 我在 hibernate 中打开了 show_sql,它为 B 插入生成了这个:

insert into B (stuff, a_id) values (?, ?)

所以看起来合法。

我对 B.a_id 的 hibernate 映射看起来像:

   <property name="aId" type="java.lang.Long" unique="true" not-null="true">
        <column name="a_id" />
    </property>

postgres 中添加的约束看起来像:

alter table B 
add constraint myfk
foreign key (a_id) 
references A;

有什么想法吗?
谢谢

编辑:我不认为休眠与此有任何关系。如果我尝试使用 sql 手动插入,我会得到同样的错误。

edit2:有一个微妙的变化 - id 字段是 int8 的并且上面有序列:

    create table A (
id int8 not null unique,
stuff varchar(10),
primary key(id)
);
create table B (
id int8 not null unique,
a_id int8 not null references A,
primary key(id)
);

create sequence a_seq;
ALTER SEQUENCE a_seq OWNED BY a.id;
ALTER TABLE a ALTER COLUMN id SET DEFAULT nextval('a_seq');

create sequence b_seq;
ALTER SEQUENCE b_seq OWNED BY b.id;
ALTER TABLE b ALTER COLUMN id SET DEFAULT nextval('b_seq');

So I have two tables:

table A
-id
-other stuff

table B
-id
-stuff
-a_id, a fk column to id in A

in hibernate, I've mapped B.a_id as a simple property (I don't want a many-to-one and get an entire A instance out, I just want the Id). So let's say I have a row in A with id=100.

if I attempt to insert a new row into B, with a_id=100, I get a postgres foreign key constraint violation saying no A exists with id=100 !

I do not understand this.
I turned on the show_sql in hibernate, and it generates this for the B insert:

insert into B (stuff, a_id) values (?, ?)

so that looks legit.

The hibernate mapping I have for B.a_id looks like:

   <property name="aId" type="java.lang.Long" unique="true" not-null="true">
        <column name="a_id" />
    </property>

the constraint added in postgres looks like:

alter table B 
add constraint myfk
foreign key (a_id) 
references A;

Any ideas?
Thank you

edit: I do not think hibernate has anything to do with this. if I try the insert by hand using sql, I get the same error.

edit2: There is a subtle twist - the id fields are int8's and have sequences on them:

    create table A (
id int8 not null unique,
stuff varchar(10),
primary key(id)
);
create table B (
id int8 not null unique,
a_id int8 not null references A,
primary key(id)
);

create sequence a_seq;
ALTER SEQUENCE a_seq OWNED BY a.id;
ALTER TABLE a ALTER COLUMN id SET DEFAULT nextval('a_seq');

create sequence b_seq;
ALTER SEQUENCE b_seq OWNED BY b.id;
ALTER TABLE b ALTER COLUMN id SET DEFAULT nextval('b_seq');

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

守不住的情 2024-11-03 21:40:55
CREATE TABLE A (id INT, other_stuff VARCHAR(20) NULL);
CREATE TABLE b (id INT, stuff VARCHAR(20) NULL, a_id INT);
ALTER TABLE A ADD CONSTRAINT PK_A PRIMARY KEY (id);
ALTER TABLE B ADD CONSTRAINT myfk FOREIGN KEY (a_id) REFERENCES A;

INSERT INTO A (id) VALUES (100);
INSERT INTO B (id, a_id) VALUES (1,100);

SELECT * FROM a JOIN b ON a.id = b.a_id;
 id  | other_stuff | id | stuff | a_id 
-----+-------------+----+-------+------
 100 |             |  1 |       |  100

我尝试在 PostgreSQL 9.0.3 中使用上述 SQL 来复制您的问题,但无法复制您的错误。您可以捕获的任何 DDL/DML 以及确切的错误消息都会有所帮助。

(当您提供更多信息时,我将继续添加信息。希望这也可以作为其他人的起点。)

CREATE TABLE A (id INT, other_stuff VARCHAR(20) NULL);
CREATE TABLE b (id INT, stuff VARCHAR(20) NULL, a_id INT);
ALTER TABLE A ADD CONSTRAINT PK_A PRIMARY KEY (id);
ALTER TABLE B ADD CONSTRAINT myfk FOREIGN KEY (a_id) REFERENCES A;

INSERT INTO A (id) VALUES (100);
INSERT INTO B (id, a_id) VALUES (1,100);

SELECT * FROM a JOIN b ON a.id = b.a_id;
 id  | other_stuff | id | stuff | a_id 
-----+-------------+----+-------+------
 100 |             |  1 |       |  100

I attempted to duplicate your problem using the above SQL in PostgreSQL 9.0.3 and I couldn't duplicate your error. Any DDL/DML that you can capture as well as the exact error message would be helpful.

(I'll keep adding info as you provide additional info. Hopefully this can serve as a starting point for someone else, too.)

七月上 2024-11-03 21:40:55

如果表 A 中的父行存在,那么 PostgreSQL 将不会抛出错误。

ID 列的生成也不重要(一旦插入父行)。

我能想到的唯一一件事是:您是否可能在不同的休眠会话中插入表 A 中的行并忘记提交?

在表 B 中插入行的另一个会话/事务将看不到表 A 中未提交的行。

直接运行语句没有问题:

postgres=> create table A (
postgres(>   id int8 not null unique,
postgres(>   stuff varchar(10),
postgres(>   primary key(id)
postgres(> );
CREATE TABLE
postgres=>
postgres=> create table B (
postgres(>   id int8 not null unique,
postgres(>   a_id int8 not null references A,
postgres(>   stuff varchar(10),
postgres(>   primary key(id)
postgres(> );
CREATE TABLE
postgres=>
postgres=> create sequence a_seq;
CREATE SEQUENCE
postgres=> ALTER SEQUENCE a_seq OWNED BY a.id;
ALTER SEQUENCE
postgres=> ALTER TABLE a ALTER COLUMN id SET DEFAULT nextval('a_seq');
ALTER TABLE
postgres=>
postgres=> create sequence b_seq;
CREATE SEQUENCE
postgres=> ALTER SEQUENCE b_seq OWNED BY b.id;
ALTER SEQUENCE
postgres=> ALTER TABLE b ALTER COLUMN id SET DEFAULT nextval('b_seq');
ALTER TABLE
postgres=>
postgres=> COMMIT;
COMMIT
postgres=> INSERT INTO a (stuff) VALUES ('a_stuff');
INSERT 0 1
postgres=> commit;
COMMIT
postgres=> select * from a;
 id |  stuff
----+---------
  1 | a_stuff
(1 row)


postgres=> INSERT INTO b (a_id, stuff) VALUES (1, 'b_stuff');
INSERT 0 1
postgres=> commit;
COMMIT;
postgres=>

If the parent row in table A is there, then PostgreSQL will not throw an error.

The generation of the ID columns should not matter either (once the parent row is inserted).

The only thing, that I can think of: did you maybe insert the row in table A in a differen hibernate session and forgot to commit that?

Another session/transaction that inserts the row in table B will not see the the uncommitted row in table A.

I have no problem running the statements directly:

postgres=> create table A (
postgres(>   id int8 not null unique,
postgres(>   stuff varchar(10),
postgres(>   primary key(id)
postgres(> );
CREATE TABLE
postgres=>
postgres=> create table B (
postgres(>   id int8 not null unique,
postgres(>   a_id int8 not null references A,
postgres(>   stuff varchar(10),
postgres(>   primary key(id)
postgres(> );
CREATE TABLE
postgres=>
postgres=> create sequence a_seq;
CREATE SEQUENCE
postgres=> ALTER SEQUENCE a_seq OWNED BY a.id;
ALTER SEQUENCE
postgres=> ALTER TABLE a ALTER COLUMN id SET DEFAULT nextval('a_seq');
ALTER TABLE
postgres=>
postgres=> create sequence b_seq;
CREATE SEQUENCE
postgres=> ALTER SEQUENCE b_seq OWNED BY b.id;
ALTER SEQUENCE
postgres=> ALTER TABLE b ALTER COLUMN id SET DEFAULT nextval('b_seq');
ALTER TABLE
postgres=>
postgres=> COMMIT;
COMMIT
postgres=> INSERT INTO a (stuff) VALUES ('a_stuff');
INSERT 0 1
postgres=> commit;
COMMIT
postgres=> select * from a;
 id |  stuff
----+---------
  1 | a_stuff
(1 row)


postgres=> INSERT INTO b (a_id, stuff) VALUES (1, 'b_stuff');
INSERT 0 1
postgres=> commit;
COMMIT;
postgres=>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文