2016-07-14 5 views
8

Использование SQLAlchemy для запросов к базе данных MySQL я получаю следующее сообщение об ошибке:Игнорировать блокировку в базе данных MYSQL в SQLAlchemy Query

sqlalchemy.exc.OperationalError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (_mysql_exceptions.OperationalError) (1205, 'Lock wait timeout exceeded; try restarting transaction')

Первого, я полагаю, что сообщение об ошибке Комментарий к «рассмотреть вопрос об использовании session.no_autoflush блока если этот флеш происходит преждевременно »- это о том, что другой сеанс помещает блокировку, а не сеанс, который я использую для моего текущего запроса? Если бы я последовал этому совету, это поможет избежать блокировок в базе данных в целом? Во-вторых, мне нужно только читать и не нужно писать изменения в результатах запроса, поэтому я хотел бы знать, как игнорировать блокировку и просто читать то, что сейчас находится в базе данных. Я считаю, что sql - это NOWAIT, но я не вижу, как это сделать в API sqlalchemy.

+0

Просьба представить операторы SQL (в обоих соединениях) и 'SHOW CREATE TABLE' и' SHOW ENGINE = InnoDB STATUS; '(если это возможно, когда проблема возникает). Из того, что вы предоставили, мы не можем сказать, почему это запирание, и многие другие важные детали. –

+0

Также укажите информацию о «no_autoflush» sqlalchemy; нам нужно выяснить, какая конструкция MySQL находится под обложками. –

+0

@RickJames нет SQL-конструкций underly [autoflush] (http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush). Это как сеанс SQLAlchemy обрабатывает состояние. Если у сеанса есть ожидающие изменения, которые еще не покраснели в БД (вставляет, обновляют, удаляют), он будет сбрасывать их в БД до запуска следующего запроса, если используется функция autoflush. Невозможно помочь OP без mcve, хотя что-то блокирует что-то и флеш, выпущенный до того, как какой-то запрос использует что-то заблокированное ... –

ответ

1

Предполагая, что вы используете mysql.connector, значение по умолчанию для свойства autocommit является ложным, что может привести к зависанию скрипта из-за другого сеанса, который ждет завершения.

SQLAlchemy использует BEGIN statements, (псевдоним START TRANSACTION), которые вызывают сеанс приобрести блокировку таблицы/базы данных и подключение будет ждать до тех пор, пока блокировка не будет получить одобрение.

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

Session = sessionmaker(bind=engine, autocommit=True) 

Другой вариант - после того, как вам создать сеанс можно выполнить SET AUTOCOMMIT=1:

s = Session() 
s.execute("SET AUTOCOMMIT=0") 

You can also try to set the autocommit property directly in the connection string:

engine = create_engine("mysql+mysqlconnector://user:[email protected]/dbname?autocommit=1") 

However I didn't test it. According to the documentations it should work.

+0

Will оцените объяснение любого голосующего голоса – Dekel

+1

Одна из первых вещей, упомянутых [в документации sqla] (http: // docs.sqlalchemy.org/en/latest/orm/session_transaction.html#autocommit-mode): «** Предупреждение ** Режим« автокоммит »должен ** не рассматриваться для общего использования **». –

+0

@ IljaEverilä, autocommit = True действительно НЕ хорошая практика, поэтому он упоминается таким образом в документации, ОДНАКО, если нет необходимости в транзакционном коде (например, для чтения), это будет много дешевле для сервера иметь эту транзакцию с autocommit = True. Тот факт, что SQLAlchemy имеет autocommit = False для каждого сеанса, не всегда является такой хорошей практикой. Более того - если вы используете движок MyISAM, нет смысла иметь транзакцию, и там еще лучше иметь autocommit = True. – Dekel

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