2015-07-13 2 views
5
SQLAlchemy v1.0.6 
cx_Oracle v5.2 

У нас возникла проблема с нашим производственным кодом на некоторое время и, наконец, сузилась до данных, возвращающихся из SQLAlchemy.SQLAlchemy иногда ошибочно возвращает пустой результат

Выполнение одного и того же запроса несколько раз иногда возвращает пустой результат. В некоторых условиях мы можем заставить его возвращать пустой результат каждый раз, когда выполняется код. Это несмотря на то, что данные в базе данных не изменились вообще и что чистые SQL-версии одного и того же запроса, запущенные непосредственно на cx_Oracle, всегда возвращают правильный результат.

Вот декларативный код 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(). Так что это похоже на какой-то вопрос времени.

Любые подсказки, что здесь происходит?

EDIT: Я упростил код, необходимый для создания ошибки. Вот он:

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 
+0

У меня была проблема несколько лет назад с некоторыми драйверами mysql, которые вызывали странные, казалось бы, недетерминированные проблемы, подобные этому. Я не могу сказать в отношении Oracle, но вы можете попробовать другой драйвер базы данных, чтобы узнать, помогает ли это? –

+0

Спасибо за предложение, Нед! – Vijchti

+0

Больше тестов показывает, что это происходит только в SQLAlchemy. Не cx_Oracle сам по себе, даже при копировании SQL, сгенерированного SQLAlchemy, а не в другой системе, которая использует JDBC для подключения к базе данных, ничего не создает эту проблему, кроме SQLAlchemy. Самое странное ... – Vijchti

ответ

4

Ответ найденный: проблема была cx_Oracle 5.2. Переустановка cx_Oracle 5.1.3 решила проблему.

Смежные вопросы