繁体   English   中英

如何使用 Oracle 数据库在 sqlalchemy 中设置查询超时?

[英]How to set a query timeout in sqlalchemy using Oracle database?

我想在 sqlalchemy 中创建查询超时。 我有一个 oracle 数据库。

我试过以下代码:

import sqlalchemy
engine = sqlalchemy.create_engine('oracle://db', connect_args={'querytimeout': 10})

我收到以下错误:

TypeError: 'querytimeout' is an invalid keyword argument for this function

我想要一个看起来像这样的解决方案:

connection.execute('query').set_timeout(10)

也许可以在 sql 查询中设置超时? 我在 pl/sql 中找到了方法,但我只需要 sql。

我如何设置查询超时?

在 Oracle 中执行此操作的方法是通过资源管理器。 看看这里

从 Sqlalchemy 为 Oracle 引擎设置连接超时的唯一方法是创建和配置 sqlnet.ora

Linux

在文件夹中创建文件sqlnet.ora

/opt/oracle/instantclient_19_9/network/admin

Windows

对于 windows,请创建这样的文件夹\network\admin

C:\oracle\instantclient_19_9\network\admin

示例sqlnet.ora文件

SQLNET.INBOUND.CONNECT_TIMEOUT = 120
SQLNET.SEND_TIMEOUT = 120
SQLNET.RECV_TIMEOUT = 120

您可以在此处找到更多参数https://docs.oracle.com/cd/E11882_01/network.112/e10835/sqlnet.htm

超时装饰器

像往常一样获取您的 session 手柄。 (注意 session 尚未真正连接。)然后,在装饰有 wrapt_timeout 的 function 中测试 session。

#!/usr/bin/env python3


from time import time
from cx_Oracle import makedsn
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql import text
from wrapt_timeout_decorator import timeout


class ConnectionTimedOut(Exception):
    pass


class Blog:

    def __init__(self):
        self.port = None

    def connect(self, connection_timeout):
        @timeout(connection_timeout, timeout_exception=ConnectionTimedOut)
        def test_session(session):
            session.execute(text('select dummy from dual'))

        session = sessionmaker(bind=self.engine())()
        test_session(session)
        return session

    def engine(self):
        return create_engine(
            self.connection_string(),
            max_identifier_length=128
        )

    def connection_string(self):
        driver = 'oracle'
        username = 'USR'
        password = 'solarwinds123'
        return '%s://%s:%s@%s' % (
            driver,
            username,
            password,
            self.dsn()
        )

    def dsn(self):
        host = 'hn.com'
        dbname = 'ORCL'
        print('port: %s expected: %s' % (
            self.port,
            'success' if self.port == 1530 else 'timeout'
        ))
        return makedsn(host, self.port, dbname)

    def run(self):
        self.port = 1530
        session = self.connect(connection_timeout=4)
        for r in session.execute(text('select status from v$instance')):
            print(r.status)
        self.port = 1520
        session = self.connect(connection_timeout=4)
        for r in session.execute(text('select status from v$instance')):
            print(r.status)


if __name__ == '__main__':
    Blog().run()

在这个例子中,网络被防火墙打开了端口 1530。 端口 1520 被阻塞并导致 TCP 连接超时。 Output:

port: 1530 expected: success
OPEN
port: 1520 expected: timeout
Traceback (most recent call last):
  File "./blog.py", line 68, in <module>
    Blog().run()
  File "./blog.py", line 62, in run
    session = self.connect(connection_timeout=4)
  File "./blog.py", line 27, in connect
    test_session(session)
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrapt_timeout_decorator.py", line 123, in wrapper
    return wrapped_with_timeout(wrap_helper)
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrapt_timeout_decorator.py", line 131, in wrapped_with_timeout
    return wrapped_with_timeout_process(wrap_helper)
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrapt_timeout_decorator.py", line 145, in wrapped_with_timeout_process
    return timeout_wrapper()
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrap_function_multiprocess.py", line 43, in __call__
    self.cancel()
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrap_function_multiprocess.py", line 51, in cancel
    raise_exception(self.wrap_helper.timeout_exception, self.wrap_helper.exception_message)
  File "/home/exagriddba/lib/python3.8/site-packages/wrapt_timeout_decorator/wrap_helper.py", line 178, in raise_exception
    raise exception(exception_message)
__main__.ConnectionTimedOut: Function test_session timed out after 4.0 seconds

警告

不要装饰调用 sessionmaker 的 function,否则会得到:

_pickle.PicklingError: Can't pickle <class 'sqlalchemy.orm.session.Session'>: it's not the same object as sqlalchemy.orm.session.Session

扫描

此实现是“连接超时”,不考虑根本原因。 在尝试所有可用的 SCAN 侦听器之前,客户端可能会超时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM