跨线程共享的 django 连接导致 ora-01000 超出最大打开游标

Posted

技术标签:

【中文标题】跨线程共享的 django 连接导致 ora-01000 超出最大打开游标【英文标题】:django connections shared across threads causes ora-01000 maximum open cursors exeeded 【发布时间】:2013-11-14 10:37:10 【问题描述】:

如果运行时间过长,我想停止执行 SQL 语句。

为了实现这一点,我破解了django.core.db.backends.oracle.base。在FormatStylePlaceholderCursor.executeexecutemany 中,而不是:

return self.cursor.execute(TIMEOUT, query, self._param_generator(params))

我愿意:

return timelimited(TIMEOUT, self.cursor.execute, query, self._param_generator(params))

timelimited 是这个配方中的一个函数:http://code.activestate.com/recipes/576780-timeout-for-nearly-any-callable/。它在单独的线程中包装一个函数(即cursor.execute)并等待TIMEOUT。如果函数没有返回,则线程停止。

通过此修改,我正在运行的应用程序在一段时间后抛出 ora-01000 最大游标超出。我在徘徊为什么包装cursor.execute 会导致这个问题,如何解决它以及这个问题的其他可用解决方案。

【问题讨论】:

“被杀”是什么意思?你能控制杀戮过程吗?为什么需要超时? Oracle 在解析查询时会创建一个执行的“程序”。这一直存在于 Oracle 的内存中,直到查询关闭或数据库连接关闭。 this thread 可能会有所帮助 @Ivan - 我的意思是调用 thread.stop()。我需要超时,因为这将连接到缓存数据库。如果缓存数据库不可用或需要很长时间才能响应,我不会等待很长时间。我想取消执行并转至主数据库。 @alko - 这实际上没有帮助。请不要我试图保护连接中断的情况 - 在其他短查询的中间发生了一些事情,所以这需要在客户端处理。 顺便说一句,您使用的是什么 python(jython/cpython/pypy 和版本)? 【参考方案1】:

我不熟悉 Django 和 Python。我可以告诉你 OCI 驱动程序为用户提供了什么。

您必须关闭查询句柄 - 或者它在 Python 中的名称。否则你会在数据库端泄漏资源 如果查询仍处于活动状态,您可以使用 OCIBreak 调用中断它。这个是线程安全的,可以从任何线程调用,无论后台线程对连接做什么 尝试检查一下,Oracle 的 Python 驱动程序是否允许您调用 OCIBreak 和 OCIReset

This 是您所需要的。 Connection.cancel()

【讨论】:

老实说,这不是我需要的东西。让我解释一下(只有四行代码,很抱歉在 cmets 中缺少格式): import cx_Oracle as db \n conn = db.connect(connect_string) \n #HERE UNPLUG YOUR ETHERNET CABLE \n conn.ping() # will永远挂起\n 好的,在这种情况下,您将面临 DCD(死连接检测)问题。有很多关于这个的文章,甲骨文也提出了一些建议。 “最佳”方法是将奇怪的子句 (ENABLE=BROKEN) 放入 tnsnames.ora 条目中。这使得 Oracle 在网络连接上使用 TCPKeepAlive。您将需要root privs。调整几个与 TCPKeepAlive 相关的内核级参数。诀窍在于 DCD 在这种情况下由 Linux 内核处理 - 这种方法确实有效。 Connection.cancel() 中断数据库服务器端的“线程”执行。这可能是如何将连接返回到池中的最快方法。当然,这仅在您没有任何网络问题时才有效。

以上是关于跨线程共享的 django 连接导致 ora-01000 超出最大打开游标的主要内容,如果未能解决你的问题,请参考以下文章

在 Apache 上的 PHP 中的线程之间共享数据

跨线程共享内存访问

如果只有一个线程使用互斥锁,跨线程的共享内存会损坏吗?

使用 Django REST 框架跨微服务共享数据库关系

使用 django 访问数据库的线程安全方法

如何在php中跨线程共享全局变量?