是否有“最佳实践”方法来检查连接状态并在需要时重新连接?#
是的,至少在我看来,因为只有一种方法没有竞争条件,那就是在重试循环中执行查询,如果出现错误,该循环会处理错误。
否则你仍然有:
PREPARE
SELECT 1;
或者你的测试语句是什么
- 网络掉线,后端崩溃,管理员重新启动服务器,无论如何
EXECUTE
- 啪。
正确的行为需要类似伪代码的东西:
while not succeeded:
try:
execute_statement()
succeeded = True
except some_database_exception:
if transaction_is_valid():
// a `SELECT 1` or `select 1 from pg_prepared_statements where name = 'blah'
// succeeded in transaction_is_valid(), so the issue was probably
// transient. Retry, possibly with a retry counter that resets the
// connection if more than a certain number of retries.
// It can also be useful to examine the exception or error state to
// see if the error is recoverable so you don't do things like retry
// repeatedly for a transaction that's in the error state.
else if test_connection_usable_after_rollback():
// Connection is OK but transaction is invalid. You might determine
// this from the exception state or by seeing if sending a `ROLLBACK`
// succeeds. In this case you don't have to re-prepare, just open
// a new transaction. This case is not needed if you're using autocommit.
else:
// If you tried a SELECT 1; and a ROLLBACK and neither succeeded, or
// the exception state suggests the connection is dead. Re-establish
// it, re-prepare, and restart the last transaction from the beginning.
reset_connection_and_re_prepare()
冗长又烦人?是的,但通常很容易包装在帮助程序或库中。其他一切仍然受制于种族。
最重要的是,如果您的应用程序在发出不止一件事的事务时,它需要记住在事务提交之前所做的所有事情,并且在出现错误时能够重试整个事务。那,或者告诉用户“哎呀,我吃掉了你的数据,请重新输入并重试”。
如果您不介意比赛并且只想通过定期检查来处理任何明显的死连接,只需将最后一次查询的时间存储在变量中即可。发出查询时,检查时间戳是否超过几分钟,如果是,则发出一个SELECT 1;
或一个查询pg_prepared_statements
来检查您准备好的语句。您要么需要准备好向用户吐出错误,要么将整个事情包装在适当的错误处理中......在这种情况下,根本没有必要进行时间检查和测试。