我正在开发一个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
有没有办法实现这个目标?如果没有,有哪些替代方案?
谢谢!
答案 0 :(得分:2)
您的脚本有两个主要问题。第一个问题是实际的:事务是特定会话的一部分,因此您的第一个psql
命令只是启动事务然后退出,没有实际效果:事务在命令完成时结束,以及后来的命令不要分享。第二个问题是概念性的:事务Y在事务X提交之前不会看到事务X中所做的更改,但是一旦事务X被提交,事务Y就会立即看到它们,即使事务Y仍然在 - 进展。这意味着,即使您的脚本成功地将整个转储包装在单个事务中,这也没有任何区别,因为您的转储仍然会看到从一个查询到下一个查询的结果不一致。 (也就是说:在事务中包含一系列SELECT
是没有意义的。只有当事务包含一个或多个DML语句UPDATE
或INSERT
或{时,事务才有意义。 {1}}峰)
但是,因为你并不真的需要你的shell脚本来遍历你的表列表;相反,你可以通过传递多个DELETE
标志,一次性给出pg_dump
所有表名:
-t
和according to the documentation,pg_dump -U postgres -h $IP_ADDRESS -p 5432 \
-t table1 -t table2 -t table3 -a --inserts MYDB >> out.sql
“即使同时使用数据库也会进行一致的备份”,因此即使确实有所帮助,您也不必担心设置事务。
(顺便说一下,pg_dump
标志也支持全局表示法;例如,-t
将匹配名称以-t table*
开头的所有表。)