我在Windows上通过VB.NET /ODBC使用PostgreSQL数据服务器,这对于存储/操作数据来说似乎是非常可靠和高度可用的解决方案。
作为初学者,我对何时打开/关闭数据库连接存有疑虑。
例如,我可以在程序启动时打开连接,并在程序执行期间保持打开状态,这可能是几天甚至几个月的持续时间。在这种情况下,我传输连接参考,以便在程序中的所有读/写功能中使用。
或者,在其他情况下,我可以打开/关闭每个函数调用或数据库操作的连接,这不需要很长时间,但会带来许多打开/关闭的情况。
现在我想得到有经验的用户推荐哪种方式更好。
1)始终保持打开连接程序执行 2)每次需要读取/保存数据时连接/关闭。
第二个但相关的问题是当我打开这样的数据库连接时:
Dim conn As New OdbcConnection
conn.ConnectionString = "Dsn=" + dbDsn + _
";database=" + mydatabase + _
";server=" + dbServer + _
";port=" + dbPort + _
";uid=" + dbUser + _
";pwd=" + dbPass
conn.Open()
... etc...
这是一种在程序中稍后查找使用“conn”引用的连接打开确切数据库的方法吗?
答案 0 :(得分:13)
长时间保持连接,但保持transactions尽可能短。
如何查找数据库
SELECT current_database()
具有容错能力的长连接
不要经常打开和关闭连接。挂在他们身上,但要准备让他们从你身下消失,例如:
您的应用必须优雅地应对连接变得无法使用,并准备在建立新连接后重新尝试操作。确保限制重试次数,这样就不会永远循环,反复使用相同的故障锤击数据库服务器。
由于连接可能随时变为无效,因此必须始终检查绝对每个数据库操作的错误代码,除非您的语言在数据库操作失败时可以抛出异常。如果可以使用异常,则只需将整个数据库操作序列包装在一个try / catch中。
如果您的应用程序非常简单并且不必对用户友好,则可以告诉用户您丢失了连接并要求他们重新启动应用程序。就个人而言,如果您选择这种方法,我认为您会对此感到遗憾,但它确实使错误处理变得更容易。
如果您的应用需要同时连接多个连接,请使用connection pool或重新设计来对单个连接进行排队操作。
具有容错功能的短交易并重试
如果您愿意,可以长时间保持连接,您应该尽可能缩短交易。长时间运行的事务会导致某些数据库系统出现问题,包括PostgreSQL - 它们会降低效率,增加锁定问题的风险等。不要让事务在用户“思考时间”上保持打开状态 - 即暂停用户交互 - 如果可能的话。如果您必须保持交易开放,请尝试暂停,如果他们决定在填写该表单的中途休假,则将用户退回到会话到期的开始。如果你认为我在开玩笑,你还没有花足够的时间来维护生产应用程序。
您的应用应准备好让任何数据库操作失败并能够重新尝试。在数据库语句成功运行后,不要丢弃应用程序对任务的了解;保留它直到整个事务成功提交。这样,如果您遇到序列化失败,您的tx被服务器取消等,您可以重新发布整个事务。
想象一下,你写了一些典型的线性数据库访问代码(伪代码,我不会说Visual Basic),如下所示:
BEGIN;
value = get_value1_from_user();
UPDATE something SET field = :value;
value = get_value2_from_user();
UPDATE somethingelse SET otherfield = :value;
COMMIT;
现在想象如果第二个UPDATE
失败会发生什么。 COMMIT
不会发生 - 如果您尝试运行它,它会改为ROLLBACK
- 而您不知道用户为get_value1_from_user()
输入的内容,因此您可以'重试。
写一些类似的东西通常更明智:
value1 = get_value1_from_user();
value2 = get_value2_from_user();
committed = false;
retries = 3;
do:
try:
BEGIN;
UPDATE something SET field = :value1;
UPDATE somethingelse SET otherfield = :value2;
COMMIT;
committed = true;
catch ...:
retries = retries - 1;
log "Failed to commit (sometask) because of (error message from database), "+retries+" left"
while not committed and retries > 0;
if not committed:
print "Tell the user I couldn't save their work"
end if;
当然,您希望对重试很聪明。发生故障后,检查以确保连接仍然存在并重新建立,然后重试(如果不存在)。检查你的语句失败的原因 - 重新尝试语法错误的语句是没有意义的。这就是SQLSTATE
的用途,在不检查消息文本的情况下区分不同类型的错误。
从不检查错误消息文本作为做出决定的方式,因为消息会被翻译并且可以在不同版本之间进行更改。
没有“已验证”的连接
在数据库开发方面不熟悉的开发人员可以通过在继续操作之前验证数据库连接来节省大量麻烦。他们发出SELECT 1
或其他内容并根据连接可用结束,因此在尝试下一次操作时不会失败。
这是假的。 “验证”和下一次操作之间存在固有的竞争条件。不仅如此,只是因为简单的验证操作成功并不意味着下一个非平凡的声明不会失败。您的应用应跟踪在事务发生期间所做的所有更改,直到提交为止,并且能够在事务失败时重试。
另一种方法是告诉用户“oops,失败。重新输入所有更改并重试”。有时这实际上是正确的事情,例如当使用乐观锁定策略时,两个正在进行的更改会发生冲突,并且您无法以编程方式安全地合并它们。不过,通常在幕后重试通常会更好。
答案 1 :(得分:4)
使用连接池,例如pgbouncer或pgpool。我们本月早些时候做了一些测试:
使用pgpool执行查询大约需要9毫秒,没有pgpool 执行相同的查询大约需要700毫秒。
差异在于查询计划的缓存。