2013-08-05 79 views
6

让我们看看下一个片段 -Python的SQLAlchemy的 - “MySQL服务器消失”

@event.listens_for(Pool, "checkout") 
def check_connection(dbapi_con, con_record, con_proxy): 

cursor = dbapi_con.cursor() 
try: 
    cursor.execute("SELECT 1") # could also be dbapi_con.ping(), 
           # not sure what is better 
except exc.OperationalError, ex: 
    if ex.args[0] in (2006, # MySQL server has gone away 
         2013, # Lost connection to MySQL server during query 
         2055): # Lost connection to MySQL server at '%s', system error: %d 
     # caught by pool, which will retry with a new connection 
     raise exc.DisconnectionError() 
    else: 
     raise 


engine = create_engine('mysql://user:[email protected]/dbname', pool_recycle = 3600,pool_size=10, listeners=[check_connection]) 

session_factory = sessionmaker(bind = engine, autoflush=True, autocommit=False) 
db_session = session_factory() 

... 
some code that may take several hours to run 
... 

db_session.execute('SELECT * FROM ' + P_TABLE + " WHERE id = '%s'" % id)   

我认为结账事件下注册checkout_connection功能将解决它,但它现在didnt 的问题我是如何告诉SQLAlchemy处理连接丢失的,所以每次我调用execute()它都会检查连接是否可用,如果不是,它会再次启动它?

---- ---- UPDATE

的SQLAlchemy的版本是0.7.4

---- ---- UPDATE

def checkout_listener(dbapi_con, con_record, con_proxy): 
    try: 
     try: 
      dbapi_con.ping(False) 
     except TypeError: 
      dbapi_con.ping() 
    except dbapi_con.OperationalError as exc: 
     if exc.args[0] in (2006, 2013, 2014, 2045, 2055): 
      raise DisconnectionError() 
     else: 
      raise 


engine = create_engine(CONNECTION_URI, pool_recycle = 3600,pool_size=10) 
event.listen(engine, 'checkout', checkout_listener) 
session_factory = sessionmaker(bind = engine, autoflush=True, autocommit=False) 
db_session = session_factory() 

session_factory发送到每个新创建的线程

class IncidentProcessor(threading.Thread): 

    def __init__(self, queue, session_factory): 
     if not isinstance(queue, Queue.Queue): 
      raise TypeError, "first argument should be of %s" (type(Queue.Queue)) 
     self.queue = queue 
     self.db_session = scoped_session(session_factory) 
     threading.Thread.__init__(self) 

    def run(self): 

    self.db_session().execute('SELECT * FROM ...') 

    ... 
     some code that takes alot of time 
    ... 

    self.db_session().execute('SELECT * FROM ...') 

现在当时间的大周期我得到的“MySQL服务器消失”错误

+0

你检查是否被解雇结账事件?你是否也用@ event.listens_for(Pool,“checkout”)装饰你的函数check_connection?这个链接可能会有所帮助http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic –

+0

哦,我忘了现在添加装饰,它似乎尝试使用该功能,但它会抛出一个异常说 - “没有实现任何:first_connect,checkin,checkout,connect” – Xeus

+0

你正在使用什么版本的sqlalchemy?你也可以在这里发布修饰过的代码和装饰器吗? –

回答

10

有一说起这个,还有这个文档描述的问题非常好听,所以我用他们推荐的方法来处理这样的错误:http://discorporate.us/jek/talks/SQLAlchemy-EuroPython2010.pdf

它看起来是这样的:

from sqlalchemy import create_engine, event 
from sqlalchemy.exc import DisconnectionError 


def checkout_listener(dbapi_con, con_record, con_proxy): 
    try: 
     try: 
      dbapi_con.ping(False) 
     except TypeError: 
      dbapi_con.ping() 
    except dbapi_con.OperationalError as exc: 
     if exc.args[0] in (2006, 2013, 2014, 2045, 2055): 
      raise DisconnectionError() 
     else: 
      raise 


db_engine = create_engine(DATABASE_CONNECTION_INFO, 
          pool_size=100, 
          pool_recycle=3600) 
event.listen(db_engine, 'checkout', checkout_listener) 
+1

嘿,我试过这个,但仍然工作几个小时后脚本得到一个点,它试图执行('选择*从...'),仍然我得到同样的错误,说MySQL已经消失 任何想法如何我能克服这个吗? – Xeus

+0

是否有可能在启动数据库连接时不通过引擎连接这个事件处理程序?另外,我看到你修改了我粘贴在这里的片段,是你在你的应用中使用的代码片段的当前版本,是你在问题中发布的片段吗? – andrean

+0

嘿我更新了我的帖子 中的代码,确切地说明了代码在我的代码中如何完成,您是否可以发现问题? – Xeus

-1

后执行的运行后,可以尝试这样的事情:

while True: 
    try: 
     db_session.execute('SELECT * FROM ' + PONY_TABLE + " WHERE id = '%s'" % incident_id) 
     break 
    except SQLAlchemyError: 
     db_session.rollback() 

如果连接消失,这将举一个例外,会议将是rollback d,它会再试一次很可能会成功。

+0

正在抛出的实际异常是-OperationalError :(OperationalError)(2006,'MySQL服务器已经消失') 我不认为我想每次都这样做我想执行sql查询 ,我确定SQLAlchemy给出了一个比这个更通用的解决方案 – Xeus

+0

你可以写一个小包装来解决这个问题,并且更具体地说明被捕获的异常。但是你是对的,很可能有更好的解决方案。这是更多的解决方法。 – Xaqq

3

尝试pool_recycle参数为create_engine

the documentation

Connection Timeouts

MySQL features an automatic connection close behavior, for connections that have been idle for eight hours or more. To circumvent having this issue, use the pool_recycle option which controls the maximum age of any connection:

engine = create_engine('mysql+mysqldb://...', pool_recycle=3600)

+0

我尝试使用pool_recycle,仍然8小时后,我收到相同的错误。 –

+0

奇怪。要不等待8小时就可以重现,请尝试将MySQL配置值wait_timeout和interactive_timeout更改为非常小的值(如10秒)。 – codeape

+0

是的,我也一样。但问题可以通过使用flask-sqlalchemy https://pythonhosted.org/Flask-SQLAlchemy/来解决。 –