sql - Postgres High 的 Principal Peril

标签 sql postgresql concurrency transactions

<分区>

在 Postgres High (PSD 9.6) 中, Nerd 和欢乐合唱团处于一场奇怪的相互依赖的 war 中。 Nerd 们密谋针对合唱团的 secret 计划。欢乐合唱团以悦耳的歌曲回应。

如果 Nerd 退缩,合唱团将永远不会回应。类似地, Nerd 们只是想激怒合唱团,所以如果合唱团没有回应, Nerd 们实际上不会调用他们的 secret 计划。

作为首席程序员,我的工作是确保一次只发生一次可能的 Nerd 叛乱尝试。我还必须确保 nerds 和 glee club 都成功或都不成功。但是那些 麻烦的 Nerd ,总是尝试 sql 注入(inject)攻击。也得防止那个。正如 Postgres High 的所有优秀领导者所做的那样,我们用 SQL 编写类(class)计划。

类(class)计划:

begin;
-- stop race conditions with a hall monitor
select from semaphore where name = 'hall_monitor' for update;

prepare nerd_rebellion (
  text, -- secret_mission
  date -- when_we_strike
) as
  update ultimate_plan
    set secret_mission = $1
    where when_we_strike = $2;

prepare glee_club_counterstrike (
  text, -- happy_song
  boolean -- kill_them_with_love
) as
  insert into song_therapy (
    happy_song,
    kill_them_with_love
  ) values (
    $1,
    $2  
  )

execute nerd_rebellion(
  'Nerds do stuff like this ; drop table song_therapy --f you glee club',
  '2017-01-01'
);
execute glee_club_counterstrike(
  'god_bless_america',
  true
);
-- let us never speak of this again ...
deallocate nerd_rebellion
deallocate glee_club_counterstrike

-- all done. Release the hall monitor
commit;

天哪,校长要做的事情太多了。我们的类时间很短,我们有所有这些准备和分配。啊。真的减少了我喝咖啡和 donut 的时间。但是我需要在单个事务中包装多个语句并使用信号量进行序列化。也不能在 SQL 注入(inject)上妥协。我没有看到更简单的解决方案。你?

最佳答案

你没有确保 Nerd 成功。 Nerd 们可能会出局(UPDATE 可能找不到行),欢乐合唱团无论如何都会唱歌。

您可以使用数据修改 CTE 或 plpgsql 函数链接这两个命令,您可以在其中根据更新的成功进行插入。

这是校长可能会使用的工具:

CREATE OR REPLACE FUNCTION nerd_strike(
      _secret_mission      text
    , _when_we_strike      date 
    , _happy_song          text
    , _kill_them_with_love boolean
   ) RETURNS void AS
$func$
BEGIN
   SELECT FROM semaphore WHERE name = 'hall_monitor' FOR UPDATE;

   UPDATE ultimate_plan
   SET    secret_mission = _secret_mission
   WHERE  when_we_strike = _when_we_strike;

   IF FOUND THEN  --  only if update actually succeeded
      INSERT INTO song_therapy (happy_song, kill_them_with_love)
      VALUES (_happy_song, _kill_them_with_love);
   END IF;
END
$func$  LANGUAGE plpgsql;

调用:

SELECT nerd_strike('Nerds do stuff like this ; drop table song_therapy --f you glee club'
                 , '2017-01-01'
                 , 'god_bless_america'
                 , true);

函数是原子的,所以它要么全部发生,要么从未发生。
参数作为传递(很像准备好的语句),因此没有机会进行 SQL 注入(inject)。

相关:

关于sql - Postgres High 的 Principal Peril,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41476167/

相关文章:

Go-lang并行段运行速度比串行段慢

PHP/MySQL。无法更新数据: Query was empty

mysql - 映射列表的 SQL 查询语法

sql - 仅显示前 n 条记录并添加 '...' FOR XML

java - EntityManager createNativeQuery 在 Java Springboot 中返回错误的结果集

postgresql - POSTGRES 中的 numeric(9,0) 和 int 有什么区别?

Java volatile 需要同步访问吗?

mysql - Sqlite 查询选择语句,其排序结果尊重 OFFSET

PHP 在 Postgresql 服务器之间以不同方式解释字符串

python - 协程 yield 与任务 yield