如果在事务中间插入数据会发生什么?

Mio*_*Mio 5 postgresql

我是数据库的新手,我对交易迷路了。例如,在我有一个sensor_log不断接收 INSERT的表的情况下,我想在一个事务中将数据移动到另外两个表。

BEGIN;

INSERT INTO sensor_log_a
SELECT id, location 
FROM sensor_log
INNER JOIN sensor_location_to_insert USING (location);

INSERT INTO sensor_log_b
SELECT id, location 
FROM sensor_log
INNER JOIN sensor_location_to_insert USING (location);

COMMIT;
Run Code Online (Sandbox Code Playgroud)

如果在事务期间插入数据或BEGIN;..COMMIT;防止这种情况发生,是否存在数据在 sensor_log_a 和 sensor_log_b 之间不同的风险?

a_h*_*ame 10

语句根据语句开始时存在的数据查看“世界”的一致视图。因此select,您的两个插入语句中的语句在运行时不会看到新行。

但是,如果运行两个语句之间(或在第一个语句开始之后)更改了表,则每个 select 语句可能会看到不同的数据,例如第一个看到 100 行,第二个看到 200 行。

如果要确保整个事务看到的数据视图一致,请使用更高的隔离级别。在你的情况下使用repeatable read就足够了。

begin transaction isolation level repeatable read;

...
commit;
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用数据修改 cte在单个语句中执行此操作:

with to_insert as (
  SELECT id, location 
  FROM sensor_log
  INNER JOIN sensor_location_to_insert USING (location)
), insert_a as (
  insert into sensor_log_a
  select *
  from to_insert
)
insert into sensor_log_b
select *
from to_insert;
Run Code Online (Sandbox Code Playgroud)

  • “但是,每个 select 语句所具有的视图可能会有所不同(例如,第一个看到 100 行,第二个看到 200 行)”,如果选择不同?我认为我没有看到你的前两段之间的区别。 (2认同)
  • @BeniMio:我的意思是,在运行第一个和第二个语句之间,基础表可能会发生变化。因此,第一个语句可能会看到与第二个语句不同的行。我改变了措辞。现在清楚了吗? (2认同)
  • `REPEATABLE READ` 绝对是这里的正确选择。 (2认同)
  • @BeniMio:单个语句在运行时不会看到对基础表的任何更改。但是 **next** 语句将看到这些更改(带有“已提交读”) (2认同)