我有一个事务,我们插入一行表foo
,然后是一行表bar
。这可以确保我们既可以写两行也可以不写。问题是bar
有一个外键到foo
。因为我们在id
插入时不知道foo
bar
,所以这会使外键约束失败。
以前我在编写Python后端时使用了像SQLAlchemy这样的工具,包括在提交事务之前刷新会话的功能 - 这允许用户派生id
{{1}在实际写任何内容之前,将它传递给foo
到INSERT
。
我的问题是,在JDBC及其Clojure包装器的上下文中,如何做到这一点?
答案 0 :(得分:2)
以前我试图在事务中使用(jdbc/query db-spec ["select id from foo where name='my_foo'"])
来派生依赖的foo
行ID。这是返回nil
,所以看起来这种明显的方法不起作用。但事实证明我使用的是db-spec
而不是事务连接,如果使用jdbc/with-db-transaction
,则绑定在向量中。
例如:
(jdbc/with-db-transaction [t-conn db-spec]
(jdbc/insert! t-conn :foo {:name "my_foo"})
(jdbc/query t-conn ["select id from foo where name='my_foo'"]))
上述表单中的query
将生成正确的行ID。
答案 1 :(得分:1)
您可以在一个查询中将值插入到两个表中,例如:
create table foo (
foo_id serial primary key,
name text);
create table bar (
bar_id serial primary key,
foo_id int references foo,
name text);
with insert_into_foo as (
insert into foo (name)
values ('some foo')
returning foo_id
)
insert into bar (foo_id, name)
select foo_id, 'some bar'
from insert_into_foo;
答案 2 :(得分:1)
这是DEFERRABLE
foreign key constraints的用途。
ALTER TABLE mytable
DROP CONSTRAINT the_fk_name;
ALTER TABLE
ADD CONSTRAINT the_fk_name
FOREIGN KEY (thecol) REFERENCES othertable(othercol)
DEFERRABLE INITIALLY IMMEDIATE;
然后
BEGIN;
SET CONSTRAINTS DEFERRED;
INSERT thetable ...;
INSERT INTO othertable ...;
-- optional, but if you do this you get any errors BEFORE commit
SET CONSTRAINTS IMMEDIATE;
COMMIT;
我建议使用initially immediate
和set constraints
,以便其余时间不创建排队触发器。它更适合性能和内存使用,而且它不会混淆那些不理解并期望延迟的cosntraints的应用程序。
如果您的框架无法解决此问题,您可以使用DEFERRABLE INITIALLY DEFERRED
代替。