2015-05-04 4 views
1

Я недавно видел MySQL server has gone away в журналах приложений для демона, который у меня работает с использованием SQLAlchemy.Соединения не закрыты SQLAlchemy

Я завершаю каждый запрос или обновление базы данных в декораторе, который должен закрыть все сеансы после завершения. Теоретически это также должно закрыть connection.

Мой декоратора выглядит

def dbop(meth): 
    @wraps(meth) 
    def nf(self, *args, **kwargs): 
     self.session = self.sm() 
     res = meth(self, *args, **kwargs) 
     self.session.commit() 
     self.session.close() 
     return res 
    return nf 

Я также инициализировать базу данных в верхней части моего сценария Python с:

def initdb(self): 
    engine = create_engine(db_url) 
    Base.metadata.create_all(engine) 
    self.sm = sessionmaker(bind=engine, 
          autocommit=False, 
          autoflush=False, 
          expire_on_commit=False) 

моему пониманию, я получаю эту ошибку, потому что мое подключение синхронизации вне. Почему это будет так, если я завершу каждый метод в этом декораторе выше? Это потому, что expire_on_commit вызывает запросы даже после закрытия соединения и может их снова открыть? Это потому, что Base.metadata.create_all вызывает выполнение SQL, который открывает соединение, которое не закрыто?

+1

'Session.close()' закрывает * session *, а не соединение. Там ['Session.invalidate()'] (http://docs.sqlalchemy.org/en/improve_toc/orm/session_api.html#sqlalchemy.orm.session.Session.invalidate), который также аннулирует связанное соединение, но я Представьте, что это происходит с довольно штрафным санкцией, я бы этого не сделал.Я предлагаю вам взглянуть на [Работа с разъединениями] (http://docs.sqlalchemy.org/en/latest/core/pooling.html#dealing-with-disconnects) и выбрать либо оптимистичную, либо пессимистическую стратегию, а также установить ' pool_recycle' для вашего движка. –

+1

Действительно @LukasGraf. Обычно вы не закрываете соединение, а сохраняете пул соединений. Даже если вы ничего не делаете, 'SQLAlchemy' определяет пул с конфигурацией по умолчанию (см. Выше на той же странице, что и ссылка) – lrnzcig

ответ

0

Ваша сессия привязана к «движку», который, в свою очередь, использует пул соединений. Каждый раз, когда SQLAlchemy требует подключения, он проверяет один из пула, и если это делается с ним, он возвращается в пул, но это не закрыт! Это общая стратегия сокращения накладных расходов при открытии/закрытии соединений. Все варианты, указанные выше, оказывают влияние только на сеанс , а не на соединение !

По умолчанию соединения в пуле остаются неопределенными.

Но MySQL автоматически закроет соединение после определенного количества неактивности (см. wait_timeout).

Проблема заключается в том, что ваш Python-процесс не будет информирован сервером MySQL о том, что соединение было закрыто, если оно попадает в таймаут бездействия. Вместо этого следующий время, когда запрос отправляется на это соединение, Python обнаружит, что соединение больше не доступно. Аналогичная ситуация может произойти, если соединение потеряно из-за других причин, например, принудительные перезагрузки службы, которые не ждут открытого закрытия открытых соединений (например, используя «немедленный» вариант при перезапуске postgres).

Это когда вы столкнетесь с исключением.

SQLAlchemy дает различные стратегии борьбы с этим, которые хорошо документированы ИНТ разделе «Dealing with Disconnects», как упомянуто @ Lukas-Graf

Если вы прыгаете через некоторые обручи вы можете получить ссылку на которое в настоящее время используется сеансом. Вы можете закрыть его таким образом, но я сильно рекомендовать против это. Вместо этого обратитесь к сеансу «Dealing with Disconnects» выше, и пусть SQLAlchemy справляется с этим для вас прозрачно. В вашем случае установка pool_recycle option может решить вашу проблему.

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