最新消息: 新版网站上线了!!!

django 数据库连接模块解析及简单长连接改造方法

¹¤×÷Öд¿·þÎñ¶ËµÄÏîÄ¿Óõ½ÁËÏ̳߳غÍdjangoµÄORM²¿·Ö¡£django µÄÊý¾Ý¿âÁ¬½ÓÔÚÿһ¸öÏß³ÌÖпªÆôÒ»·Ý£¬²¢ÔÚ²éѯÍê±Ïºó×Ô¶¯¹Ø±ÕÁ¬½Ó¡£

Ï̳߳ش¦ÀíÈÎÎñʱ£¬Õý³£Ê¹ÓõÄÁ¬½ÓÖв»»á±»¹Ø±Õ£¬µ«ÓÉÓÚÊý¾Ý¿â¶ËÓÐ×Á¬½Óʱ¼äµÄÏÞÖÆ£¨Ä¬ÈÏΪ8Сʱ£©£¬ÔÚ³¬Ê±ºó»á·¢ÉúInterfaceError: (0, '')(Á¬½Ó¹Ø±ÕºóʹÓÃÁ¬½Ó/Óαê)»òError(2006, 'MySQL server has gone away')£¨mysql ·þÎñÆ÷Ö÷¶¯¹Ø±ÕÁ¬½Ó£©ÕâÀà´íÎó£¬ËùÒÔÒ»°ã»áÔÚÿ¸öÈÎÎñÏß³ÌÖе÷ÓÃdjango.db.connection.close()½øÐйرղÙ×÷¡£

µ«¶ÔÓÚÆµ·±½øÐÐÊý¾Ý¿âÁ¬½Ó²¢²Ù×÷Êý¾Ý¿âµÄÒµÎñ£¬·´¸´´´½¨Á¬½Ó²¢²»ÊǺõÄÑ¡Ôñ£¬ÕâÖÖ³¡¾°Ï¿ÉÒÔ¿¼Âǽ«Á¬½Ó¸ÄÔìΪ³¤Á¬½Ó¡£

1. django ´úÂëµÄÔĶÁ±Ê¼Ç

django.db.__init__.py 
#¶ÔÏó£º
connections = ConnectionHandler()
connection = DefaultConnectionProxy()
# º¯Êý
# ÖØÖòéѯ¼Ç¼»º´æ
def reset_queries(**kwargs):
 pass
# ¹Ø±Õ²»¿ÉÓûò³¬Ê±(Èç¹ûÓÐÉèÖà CONN_MAX_AGE)Á¬½Ó
def close_old_connections(**kwargs):
 pass
# ÐźÅ
# ÔÚÇëÇó¿ªÊ¼»òÍê³Éʱ×Ô¶¯µ÷ÓÃÏàÓ¦´¦Àíº¯Êý
signals.request_started.connect(reset_queries)
signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

ÖØµãÊÇconnectionsºÍconnectionÁ½¸öʵÀý

connections ÊÇ ConnectionHandlerÀà

connections.all()»á¸ø³öÒ»¸öÁÐ±í£¬ÀïÃæµÄÔªËØÎªDatabaseWrapperÀà

ConnectionHandlerÄÚÖöÔÏó¼°Á¬½Ó¹ÜÀí£º

def __init__()£º
 self._connections = local()

# Á¬½Ó°ü×°ÀàÀïµÄÁ¬½ÓÊǸù¾ÝÅäÖÃÇé¿öʹÓÃÏàÓ¦µÄÁ¬½Ó
def __getitem__(self, alias):
 '''ÂÔ'''
 db = self.databases[alias]
 backend = load_backend(db['ENGINE'])
 conn = backend.DatabaseWrapper(db, alias)
 setattr(self._connections, alias, conn)

# ·µ»ØËù¹ÜÀíµÄÊý¾Ý¿âÁ¬½Ó
# ¹ÜÀí·½Ê½£º·ÖÊý¾Ý¿â£¬Ï̹߳ÜÀíÁ¬½Ó 
def all(self):
 return [self[alias] for alias in self]

# ¹Ø±ÕËùÓÐÊý¾Ý¿âÁ¬½Ó
def close_all(self):
 for alias in self:
  try:
   connection = getattr(self._connections, alias)
  except AttributeError:
   continue
  connection.close()

threading.local ÊÇÒ»¸öÈ«¾Ö±äÁ¿£¬localµÄÊôÐÔÊÇ·ÇÏ̹߳²ÏíµÄ£¬Ò²¾ÍÊÇÔÚÿһ¸öÏß³ÌÖж¼»áÓе¥¶ÀÒ»¸öÊý¾Ý¿âÁ¬½ÓʵÀý´´½¨£¬ÒòΪ´úÀí¼°°ü×°µÄÔ­Òò£¬¸ÃÁ¬½ÓʵÀýΪ¶ÔÓ¦backendÀïµÄÁ¬½Ó£¨±ÈÈ磬pymysql.connections.Connection£©¡£

ÔÚÏ̳߳صÄÇé¿öÏ£¬close_old_connections·½·¨ÊDz»Äܽ«Ïß³ÌÖеÄÊý¾Ý¿âÁ¬½Ó¹Ø±ÕµÄ¡£

connectionÊÇDefaultConnectionProxyÀàµÄʵÀý£¬Êµ¼ÊÊÇDatabaseWrapperµÄʵÀý 
£¨Ê¹ÓÃÁËpymysql¿â£ºimport pymysql; pymysql.install_as_MySQLdb£© 
DefaultConnectionProxy¨C>DatabaseWrapper¨C>pymysql.connections.Connection(¸ù¾ÝconnectionsµÄ´¦Àíµ÷ÓÃÏàÓ¦µÄÊý¾Ý¿âÁ¬½Ó°ü) 
connectionÓм¸¸ö¹Ø¼ü·½·¨ºÍÊôÐÔ

connection.connection = '±»°ü×°µÄpymysql.connections.ConnectionʵÀý`
connection.close_at = None if max_age is None else time.time() + max_age # ÉèÖõÄÁ¬½Ó¹Ø±Õʱ¼ä

connection.connect()# »ñÈ¡Á¬½Ó
connection.cursor() # »ñÈ¡Óαê
connection.close()# ¹Ø±ÕÁ¬½Ó

2. ½«Êý¾Ý¿âÁ¬½Ó¸ÄÔìΪ³¤Á¬½Ó

max_age£¨CONN_MAX_AGE£© ÊÇ¿ÉÒÔÔÚsettingsÀïÃæÅäÖõġ£

ÓÉÓÚ¶à¸ö·þÎñ¹²ÓÃÒ»Ì×ÅäÖ㬠ËùÒÔ¿¼ÂÇÖ±½ÓÔÚ³ÌÐòÀïÐÞ¸Ä

È«¾Ö±äÁ¿

max_age = 7 * 3600 

ÔÚÏß³ÌÄÚ¿ªÊ¼Ê±×öÏÂÅжϣº

if not db.connection.connection or db.connection.close_at < time.time():
 db.connection.close()
 db.connection.connect()
 db.connection.close_at = time.time() + max_age
 print "A new conn creates !"
else:
 print "Still old conn!"

ÕâÑùÿ¸öÏ̳߳ØÖеÄÏ̻߳áÑ­»·Ö´ÐÐÈÎÎñ²¢Ö»Ê¹ÓÃͬһ¸öÁ¬½Ó£¬²¢¿ÉÒÔ¿ØÖÆÔÚ×Ô¼ºÐèÒªµÄÁ¬½Óʱ³¤ºó¸ü»»Á¬½Ó¡£

Õë¶ÔÏ̳߳صÄÇé¿ö£¬close_old_connections»ù±¾Ã»É¶Óô¦, ¿ÉÒÔÌø¹ý¸Ã´¦Àí

django.db.close_old_connections = lambda **kwargs : None

ÒÔÉÏÕâÆªdjango Êý¾Ý¿âÁ¬½ÓÄ£¿é½âÎö¼°¼òµ¥³¤Á¬½Ó¸ÄÔì·½·¨¾ÍÊÇС±à·ÖÏí¸ø´ó¼ÒµÄÈ«²¿ÄÚÈÝÁË£¬Ï£ÍûÄܸø´ó¼ÒÒ»¸ö²Î¿¼£¬Ò²Ï£Íû´ó¼Ò¶à¶àÖ§³Ö½Å±¾Ö®¼Ò¡£

转载请注明:谷谷点程序 » django 数据库连接模块解析及简单长连接改造方法