簡體   English   中英

SQLAlchemy偶爾會錯誤地返回一個空結果

[英]SQLAlchemy occasionally erroneously returns an empty result

SQLAlchemy v1.0.6 
cx_Oracle v5.2

我們在生產代碼上遇到了一段時間的問題,最后將其縮小到SQLAlchemy的數據。

多次運行相同的查詢有時會返回空結果。 在某些情況下,我們可以在每次執行代碼時返回一個空結果。 盡管事實上數據庫中的數據根本沒有改變,並且直接在cx_Oracle上運行的同一查詢的純SQL版本總是返回正確的結果。

這是SQLAlchemy的聲明代碼:

class Database:
    def __init__(self, service_name, database, username, password):
        """
        service_name (str): The service name as defined in tnsnames.ora.
        database (str): The database within the chosen service.
        """
        self.engine = create_engine(
            r'oracle+cx_oracle://{username}:{password}@{service_name}'.format(username=username, password=password,
                                                                              service_name=service_name),
            case_sensitive=False)
        self.session_maker = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)

        # Database name must be injected into every table definition; this is why tables must be procedurally generated.
        self.Base = declarative_base()  # base class for all database tables
        self.build_tables(database)

    def make_session(self):
        """Create a read-only session for the database."""
        def readonly_abort():
            raise Exception('writing is prohibited; db is read-only')

        session = self.session_maker()
        session.flush = readonly_abort
        return session

    def build_tables(self, database):
        class Lot(self.Base):
            __tablename__ = 'lot'
            __table_args__ = {'schema': database}
            lot_key = Column(Integer, primary_key=True)
            lot_id = Column(String, name='lot_id')

        self.lot = Lot

這是測試代碼:

def sqlalchemy_test():
    db = dp_orm.Database(service_name, database)
    session = db.make_session()
    cursor = session.query(db.lot)
    results = cursor.first()
    if results is None:
        raise Exception

def cx_oracle_test():
    import cx_Oracle
    import set_environment_variables
    conn = cx_Oracle.Connection(username, password, service_name)
    cursor = conn.cursor()

    c = cursor.execute('SELECT * FROM {}.lot WHERE rownum <= 1'.format(database))
    results = list(c)
    if len(results) != 1:
        raise Exception

第一個函數sqlalchemy_test將在大約50%的時間內出錯。 第二個函數cx_oracle_test尚未出錯。 現在這里有趣的是:如果我們在cursor = session.query(db.lot)results = cursor.first()之間引入幾秒鍾的暫停,問題就會消失。 所以它看起來像某種時間問題。

有什么想法在這里發生了什么?

編輯:我已經簡化了創建錯誤所需的代碼。 這里是:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Fix environment variables
import os
try:
    del os.environ['ORACLE_HOME']
except KeyError:
    pass
os.environ['TNS_ADMIN'] = r'C:\product\11.1.0\client_1\network\admin'
os.environ['PATH'] = r'C:\product\11.1.0\client_1\BIN;' + os.environ['PATH']

engine = create_engine(r'oracle+cx_oracle://{username}:{password}@{service_name}'.format(username='USER', password='PASSWORD', service_name='SERVICE'))
session_maker = sessionmaker(bind=engine)
base_class = declarative_base()

class Lot(base_class):
    __tablename__ = 'lot'
    __table_args__ = {'schema': 'SCHEMA_NAME'}
    lot_key = Column(Integer, primary_key=True)
    lot_id = Column(String)

session = session_maker()
cursor = session.query(Lot)
result = cursor.first()
if result is None:
    raise Exception

答案發現:問題是cx_Oracle 5.2。 重新安裝cx_Oracle 5.1.3解決了這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM