SQLAlchemy KeyError при использовании пула соединений - PullRequest
2 голосов
/ 17 апреля 2020

Я создал класс репозитория для Person с указанным ниже методом:

def find_by_order_id(self, order_id: str) -> [Person]:
    results = []

    client_table = Table(TBL_CLIENT, self._metadata, autoload=True,
                             autoload_with=self._connection)
    order_table = Table(TBL_ORDER, self._metadata, autoload=True,
                             autoload_with=self._connection)

    query = select([client_table.c.first_name, client_table.c.last_name, client_table.c.date_of_birth])
    .select_from(
        order_table.join(client_table, client_table.c.order_id = order_table.c.order_id)
    ).where(order_table.c.order_id == order_id).distinct()

    for row in self._connection.execute(query).fetchall():
        results.append(dict(row))

    return results

по какой-то странной причине, которую я не могу объяснить, иногда я получаю KeyError из SQLAlchemy для ключа, который фактически существует, когда Я отлаживаю код:

File "/home/tghasemi/miniconda3/envs/myproj/lib/python3.6/site-packages/sqlalchemy/util/_collections.py", line 210, in __getattr__
    return self._data[key]
KeyError: 'order_id'

Я заметил, что это происходит только тогда, когда я извлекаю соединение из пула соединений во время многопоточности (каждый поток использует только одно соединение - я знаю, что соединения не являются поточно-безопасными):

if use_pooling:
        self._engine = create_engine(connection_string, pool_size=db_pool_size,
                                     pool_pre_ping=db_pool_pre_ping, echo=db_echo)
else:
        self._engine = create_engine(connection_string, echo=db_echo)

Учитывая тот факт, что ключ существует (даже проверен, когда возникает исключение), когда я ставлю точку останова, где происходит исключение, я подозреваю, что загрузка таблицы еще не завершена, когда создается запрос.

Кто-нибудь знает, почему может произойти нечто подобное? Я сдался!

1 Ответ

1 голос
/ 20 апреля 2020

Что ж, думаю, мне удалось решить проблему.

Что-то, о чем я не упомянул в своем вопросе (фактически я не думал об этом как о возможности), заключалось в том, что и объект Engine, и объект MetaData взяты из класса Singleton, который я создал для своей базы данных:

class Database(metaclass=SingletonMetaClass):

    def __init__(self, config: Config, use_pooling: bool = True, logger: Logger = None):
        # Initializing the stuff here ...


    @property
    def metadata(self): # used to return self._metadata here 
        return MetaData(self._engine, reflect=False, schema=self._db_schema)

    @property
    def engine(self):
        return self._engine

Хотя в официальной документации SQLAlchemy говорится, что объект MetaData является потокобезопасным для операций чтения, но по какой-то причине в моем случае (который читается как операция) это было причиной этой проблемы. Каким-то образом после того, как я не поделился этим объектом с моими потоками, проблема исчезла (не на 100% уверен, что она буквально исчезла, но больше не происходит).

...