简体   繁体   English

Postgres 在单个事务中插入之前删除

[英]Postgres delete before insert in single transaction

PostgreSQL DB: v 9.4.24 PostgreSQL 数据库:v 9.4.24

create table my_a_b_data ... // with a_uuid, b_uuid, and c columns

NOTE: the my_a_b_data keeps the references to a and b table.注意:my_a_b_data 保留对 a 和 b 表的引用。 So it keeps the uuids of a and b.所以它保留了a和b的uuid。

where: the primary key (a_uuid, b_uuid)其中: primary key (a_uuid, b_uuid)

there is also an index :还有一个索引

create unique index my_a_b_data_pkey
    on my_a_b_data (a_uuid, b_uuid);

In the Java jdbc-alike code , in the scope one single transaction: (start() -> [code (delete, insert)] ->commit()]) ( org.postgresql:postgresql:42.2.5 driver )类似 Java jdbc 的代码中,在一个事务的范围内: (start() -> [code (delete, insert)] ->commit()]) ( org.postgresql:postgresql:42.2.5 driver )

delete from my_a_b_data where b_uuid = 'bbb';
insert into my_a_b_data (a_uuid, b_uuid, c) values ('aaa', 'bbb', null);

I found that the insert fails, because the delete is not yet deleted.我发现插入失败了,因为删除还没有删除。 So it fails because it can not be duplicated.所以它失败了,因为它不能被复制。

Q: Is it is some kind of limitation in PostgreSQL that DB can't do a delete and insert in one transaction because PostgreSQL doesn't update its indexes until the commit for the delete is executed, therefore the insert will fail since the id or key (whatever we may be using) already exists in the index?问: DB 不能在一个事务中进行删除和插入是PostgreSQL中的某种限制吗,因为 PostgreSQL 在执行删除提交之前不会更新其索引,因此插入将失败,因为 id 或键(无论我们使用什么)已经存在于索引中?

What would be possible solution?可能的解决方案是什么? Splitting in two transactions?分成两笔交易?

UPDATE: the order is exactly the same.更新:订单完全相同。 When I test the sql alone in the SQL console.当我在 SQL 控制台中单独测试 sql 时。 It works fine.它工作正常。 We use JDBI library v 5.29.我们使用 JDBI 库 v 5.29。

there it looks like this:它看起来像这样:

 @Transaction
 @SqlUpdate("insert into my_a_b_data (...; // similar for the delete
 public abstract void addB() ..

So in the code:所以在代码中:

this.begin();
this.deleteByB(b_id);
this.addB(a_id, b_id);
this.commit();

I had a similar problem to insert duplicated values and I resolved it by using Insert and Update instead of Delete.我在插入重复值时遇到了类似的问题,我通过使用 Insert 和 Update 而不是 Delete 解决了这个问题。 I created this process on Python but you might be able to reproduce it:我在 Python 上创建了这个过程,但你可以重现它:

  1. First, you create a temporary table like the target table where you want to insert values, the difference is that this table is dropped after commit.首先,你创建一个临时表,就像你要插入值的目标表,不同的是这个表在提交后被删除。

     CREATE TEMP TABLE temp_my_a_b_data (LIKE public.my_a_b_data INCLUDING DEFAULTS) ON COMMIT DROP;
  2. I have created a CSV (I had to merge different data to input) with the values that I want to input/insert on my table and I used the COPY function to insert them to the temp_table ( temp_my_a_b_data ).我创建了一个 CSV(我必须将不同的数据合并到输入中),其中包含我想在我的表中输入/插入的值,并且我使用COPY函数将它们插入到 temp_table ( temp_my_a_b_data ) 中。

    I found this code on this post related to Java and COPY PostgreSQL - \copy command :我在这篇与 Java 和 COPY PostgreSQL - \copy 命令相关的帖子中找到了这段代码:

     String query ="COPY tmp from 'E://load.csv' delimiter ','";
  3. Use the INSERT INTO but with the ON_CONFLICT clause which you can decide to do an action when the insert cannot be done because of specified constrains, on the case below we do the update:使用 INSERT INTO 但使用ON_CONFLICT子句,您可以决定在由于指定约束而无法完成插入时执行操作,在下面的情况下我们进行更新:

     INSERT INTO public.my_a_b_data SELECT * FROM temp_my_a_b_data ON CONFLICT (a_uuid, b_uuid,c) DO UPDATE SET a_uuid = EXCLUDED.a_uuid, b_uuid = EXCLUDED. c = EXCLUDED.c;`

Considerations:注意事项:

I am not sure but you might be able to perform the third step without using the previous steps, temp table or copy from.我不确定,但您可以在不使用前面的步骤、临时表或从中复制的情况下执行第三步。 You can just a loop over the values:您可以只循环遍历这些值:

INSERT INTO public.my_a_b_data VALUES(value1, value2, null) 
ON CONFLICT (a_uuid, b_uuid,c) DO UPDATE 
   SET a_uuid = EXCLUDED.a_uuid, 
       b_uuid = EXCLUDED.b_uuid, c = EXCLUDED.c;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM