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

Abbiamo avuto un problema sul nostro codice di produzione per un po 'e infine lo abbiamo ridotto ai dati provenienti da SQLAlchemy.SQLAlchemy occasionalmente restituisce erroneamente un risultato vuoto

L'esecuzione della stessa query più volte a volte restituisce un risultato vuoto. In alcune condizioni, è possibile ottenere che restituisca un risultato vuoto ogni volta che il codice viene eseguito. Ciò nonostante il fatto che i dati nel database non siano stati modificati e che le versioni puramente SQL della stessa query eseguite direttamente su cx_Oracle restituiscano sempre il risultato corretto.

Ecco il codice dichiarativo per 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 

E qui è il codice di prova:

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 

La prima funzione, sqlalchemy_test, avrà errore circa il 50% del tempo. La seconda funzione, cx_oracle_test, non è ancora stata errata. Ora ecco cosa è interessante: il problema scompare se introduciamo una pausa per diversi secondi tra cursor = session.query(db.lot) e results = cursor.first(). Quindi sembra una sorta di problema di temporizzazione.

Qualsiasi indizio cosa sta succedendo qui?

MODIFICA: Ho semplificato il codice necessario per creare l'errore. Eccolo:

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

Ho avuto un problema anni fa con alcuni driver mysql che causavano problemi strani, apparentemente non deterministici come questo. Non posso dire per quanto riguarda Oracle, ma potresti voler provare un driver di database diverso per vedere se questo aiuta? –

+0

Grazie per il suggerimento, Ned! – Vijchti

+0

Altri test dimostrano che ciò accade solo in SQLAlchemy. Non cx_Oracle da solo, nemmeno quando si copia l'SQL generato da SQLAlchemy, non in un sistema diverso che utilizza un JDBC per connettersi al database - niente crea questo problema eccetto SQLAlchemy. La cosa più strana ... – Vijchti

risposta

4

Risposta trovata: il problema era cx_Oracle 5.2. La reinstallazione di cx_Oracle 5.1.3 ha risolto il problema.