【问题标题】:Using Postgres transactions in linux shell script在 linux shell 脚本中使用 Postgres 事务
【发布时间】:2012-08-24 20:06:39
【问题描述】:

我正在开发一个 shell 脚本,它遍历一系列 Postgres 数据库表名并转储表数据。例如:

# dump data

psql -h $SRC_IP_ADDRESS -p 5432 -U postgres -c "BEGIN;" AWARE

do
 :
 pg_dump -U postgres -h $IP_ADDRESS -p 5432 -t $i -a --inserts MYDB >> \
 out.sql
done

psql -h $IP_ADDRESS -p 5432 -U postgres -c "COMMIT;" MYDB

不过,我担心并发访问数据库。由于 Postgres 没有数据库锁,我尝试在循环周围包裹一个 BEGIN 和 COMMIT(使用 psql,如上所示)。这导致来自 psql 命令的错误消息,说:

WARNING:  there is no transaction in progress

有什么方法可以实现吗?如果没有,有什么替代方案?

谢谢!

【问题讨论】:

  • 我不久前写过这个话题。简短的版本是“驱动 psql 作为与 coproc 命令的协同进程,或使用支持连接到 Pg 的脚本语言。请参阅 stackoverflow.com/a/8305578/398670 。但是,如果你是使用 pg_dump,它只对 psql 有用。
  • 顺便说一句,有一种方法可以将所有其他用户(超级用户除外)锁定在数据库之外。您可以在数据库中为除您自己以外的所有人使用REVOKECONNECT(尽管超级用户始终可以连接),然后在针对pg_stat_activity 的查询中使用pg_terminate_backend(pid) 启动其他所有人。我承认,这不是微不足道的。在这种情况下,我认为无论如何您都在用这种方法完全错误地吠叫,请参阅 ruakh 的回答。

标签: linux postgresql shell


【解决方案1】:

您的脚本有两个主要问题。第一个问题是实际的:事务是特定会话的一部分,所以你的第一个 psql 命令,它只是启动一个事务然后退出,没有实际效果:事务在命令完成时结束,后面的命令不会分享它。第二个问题是概念上的:在事务 X 提交之前,事务 X 中所做的更改不会被事务 Y 看到,但是一旦事务 X 提交,它们就会立即被事务 Y 看到,即使事务 Y 仍然在-进步。这意味着,即使您的脚本确实成功地将整个转储包装在一个事务中,这也不会产生任何影响,因为您的转储仍然可以看到从一个查询到下一个查询的不一致结果。 (即:将一系列SELECTs包装在一个事务中是没有意义的。一个事务只有包含一个或多个DML语句,UPDATEs或INSERTs或DELETEs才有意义。)

但是,因为您实际上并不需要您的 shell 脚本来遍历您的表列表;相反,您可以通过传递多个 -t 标志一次给 pg_dump 所有表名:

pg_dump -U postgres -h $IP_ADDRESS -p 5432 \
    -t table1 -t table2 -t table3 -a --inserts MYDB >> out.sql

according to the documentationpg_dump“即使在同时使用数据库时也会进行一致的备份”,因此即使有帮助,您也不必担心设置事务。

(顺便说一下,-t 标志也支持 glob 表示法;例如,-t table* 将匹配名称以 table 开头的所有表。)

【讨论】:

  • 嗨 ruakh,感谢您的建议。我正在遍历这些表,因为我需要转储输出在恢复时以特定顺序排列。虽然 pg_dump 仅执行 SELECT,但我也有一个循环执行查询以将 SELECT 查询的数据插入到临时表中。这也是我关心的问题。最后,当我使用 psql 恢复转储文件时,这是作为安全事务执行的吗?
  • @littleK:首先——与你的评论无关——我已经修正了我原来的答案中的一些错误。其次 - 当你说你说“当我恢复它时需要转储输出以特定顺序”时,你想到什么样的顺序?因为我只是玩了一点,虽然我在文档中没有看到任何关于此的内容,但它看起来pg_dump 强调以与外键约束一致的顺序转储表,我无法想象你还需要什么其他的命令。第三——当你恢复数据时,你当然可以[继续]
  • [continued] 将其包装在事务中,但我无法想象您为什么需要这样做。我的意思是,通常,如果您从备份中恢复,整个系统会处于离线状态,直到一切都恢复为止。
  • 顺便说一下,根据文档,--inserts“会使恢复非常慢;它主要用于制作可以加载到非 PostgreSQL 数据库中的转储。”如果您打算直接使用psql 来恢复数据,COPY 语句可能会更好。
  • 感谢您的帮助。我将切换到使用 COPY 语句。当我在没有显式循环每个表的情况下尝试转储时,还原时出现键约束错误,并且转储中的顺序似乎是按字母顺序排列的。不过,我会重新审视这一点。当文档说 pg_dump 进行一致的备份时,即使同时执行,这是否意味着它将像以前一样转储任何表数据,例如并发插入?感谢您与我分享您的知识,这很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-05
  • 2013-12-13
相关资源
最近更新 更多