簡體   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