【问题标题】:How can two rows be written atomically when one row has a foreign key into the other?当一行有一个外键到另一行时,如何原子地写入两行?
【发布时间】:2016-05-22 23:31:18
【问题描述】:

我有一个事务,我们插入一行表foo,然后插入一行表bar。这确保我们要么写两行,要么都不写。问题在于bar 有一个指向foo 的外键。因为在插入bar 时我们不知道fooid,所以外键约束失败。

以前我在编写 Python 后端时使用过 SQLAlchemy 之类的工具,其中包括在提交事务之前刷新会话的能力——这允许用户派生 fooid 并将其传递到INSERTbar 在实际写任何东西之前。

我的问题是,在 JDBC 及其 Clojure 包装器的上下文中,如何做到这一点?

【问题讨论】:

    标签: postgresql jdbc clojure


    【解决方案1】:

    之前我试图在事务中使用(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。

    【讨论】:

      【解决方案2】:

      您可以在一个查询中将值插入两个表中,例如:

      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;
      

      【讨论】:

        【解决方案3】:

        这是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 immediateset constraints,以便在其余时间不要创建排队触发器。它对性能和内存使用更好,而且不会混淆不理解和期望延迟 cosntrains 的应用程序。

        如果您的框架无法解决这个问题,您可以改用DEFERRABLE INITIALLY DEFERRED

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-12
          • 1970-01-01
          • 2020-09-22
          • 1970-01-01
          • 1970-01-01
          • 2017-01-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多