为什么80%的码农都做不了架构师?>>>   

最近遇到一个很蛋疼的问题,写了一个后台管理系统, 由于是后台管理系统,所以使用频率不是很高,当django程序在闲置一段时间后,再次打开后台系统,就变得很慢,然后又好了。查了很多方面,从模板引擎到请求(request),再到django配置,nginx等等,都没有查出原因。虽然也查过是不是数据库的原因,但都因为查的不够深入,没有查出所以然。

有一次在处理权限问题时,不断地追朔源代码,由于我使用的是dbroute来控制权限,最后定位到了这个db(具体目录:/usr/local/lib/python2.7/dist-packages/django/db/__init__.py),里面的代码有关于连接的,不看不知道,看了后菊花一紧。我去!原来django每次查询的时候就连一次数据库,而且查询完成之后就立马关掉,真搞不懂作者是怎么想的。每次查询建一次连接不是很耗时间吗?源代码如下:

from django.conf import settings
from django.core import signals
from django.core.exceptions import ImproperlyConfigured
from django.db.utils import (ConnectionHandler, ConnectionRouter,load_backend, DEFAULT_DB_ALIAS, DatabaseError, IntegrityError)__all__ = ('backend', 'connection', 'connections', 'router', 'DatabaseError','IntegrityError', 'DEFAULT_DB_ALIAS')if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:raise ImproperlyConfigured("You must define a '%s' database" % DEFAULT_DB_ALIAS)connections = ConnectionHandler(settings.DATABASES)router = ConnectionRouter(settings.DATABASE_ROUTERS)# `connection`, `DatabaseError` and `IntegrityError` are convenient aliases
# for backend bits.# DatabaseWrapper.__init__() takes a dictionary, not a settings module, so
# we manually create the dictionary from the settings, passing only the
# settings that the database backends care about. Note that TIME_ZONE is used
# by the PostgreSQL backends.
# We load all these up for backwards compatibility, you should use
# connections['default'] instead.
class DefaultConnectionProxy(object):"""Proxy for accessing the default DatabaseWrapper object's attributes. If youneed to access the DatabaseWrapper object itself, useconnections[DEFAULT_DB_ALIAS] instead."""def __getattr__(self, item):return getattr(connections[DEFAULT_DB_ALIAS], item)def __setattr__(self, name, value):return setattr(connections[DEFAULT_DB_ALIAS], name, value)connection = DefaultConnectionProxy()
backend = load_backend(connection.settings_dict['ENGINE'])# Register an event that closes the database connection
# when a Django request is finished.
def close_connection(**kwargs):# Avoid circular importsfrom django.db import transactionfor conn in connections:# If an error happens here the connection will be left in broken# state. Once a good db connection is again available, the# connection state will be cleaned up.transaction.abort(conn)connections[conn].close()
signals.request_finished.connect(close_connection)# Register an event that resets connection.queries
# when a Django request is started.
def reset_queries(**kwargs):for conn in connections.all():conn.queries = []
signals.request_started.connect(reset_queries)# Register an event that rolls back the connections
# when a Django request has an exception.
def _rollback_on_exception(**kwargs):from django.db import transactionfor conn in connections:try:transaction.rollback_unless_managed(using=conn)except DatabaseError:pass
signals.got_request_exception.connect(_rollback_on_exception)

发现它是接收到了一个关闭信号后就立马关闭,其实也就是每一次django请求,它就连接一次和查询一次。网上查了下资料,有个人是这样解决的:

在django项目中的__init__.py文件中加入如下代码来实现:

from django.core import signals
from django.db import close_connection  # 取消信号关联,实现数据库长连接
signals.request_finished.disconnect(close_connection)

它采用的原理是最后一行代码相关的Signal对象,其中还有一个disconnect方法,对应实现取消信号关联。

我照着他的实现来做,发现不行,在闲置几小时后,打开后台依然需要10秒左右。由于我使用的是fastcgi来运行django,可能django在没有动静的时候,fastcgi就把它挂起,所以就还会去重新建立连接。如果使用supervisord来运行,估计不会。

既然这个方法不行,那就再看一下它的源码,发现backends目录下面有mysql,oracle,postgresql_psycopg2,sqlite3等,于是选择msql进去看一下base.py文件。发现django是直接封装MySQLdb,每创建一个MySQLdb对象其实也就进行了一次连接。能不能像线程池一样,一次性创建多个MySQLdb对象呢?答案是肯定的。sqlalchemy有个pool可以让数据库保持长连接,那就直接把这个文件里的Database改成sqlalchemy的pool。当然,我们不能暴力地修改去修改源码。因为这个模块是用来建立数据库连接的,所以可以独立出来。其实很简单,只需要修改base.py 文件几处就行。实现方法如下:

把django/db/backends/mysql目录下的文件全部拷贝出来,放在项目的一个libs/mysql下面,然后修改base.py文件。找到

try:    import MySQLdb as Database
except ImportError as e:    from django.core.exceptions import ImproperlyConfigured    raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)

这段代码,在下面添加:

from sqlalchemy import pool
Database = pool.manage(Database)

基本上就可以了。如果还想再修改,就找到

self.connection = Database.connect(**kwargs)

把它注释掉,添加

 self.connection = Database.connect(host=kwargs.get('host', '127.0.0.1'),port=kwargs.get('port', 3306),user=kwargs['user'],db=kwargs['db'],passwd=kwargs['passwd'],use_unicode=kwargs['use_unicode'],charset='utf8')

再修改一下settings.py的数据库配置,把django.db.backends.mysql改为libs.mysql。至此,世界美好了很多。

声明:本博客也发表在http://descusr.cnblogs.com/p/3566935.html,都是原创。

转载于:https://my.oschina.net/gongju/blog/203142

使django与数据库保持长连接相关推荐

  1. Django的数据库创建、连接与迁移

    一.Django默认初始数据库为sqlite3数据库: 开始创建sqlite3数据库: 连接数据库: file的文件路径需与自己的路径一致: 二.Django创建MySQL数据库: 1.安装MySQL ...

  2. TCP协议的长连接和短连接详解

    一.前言 TCP在真正开始进行数据传输之前,Server 和 Client 之间必须建立一个连接.当数据传输完成后,双方不再需要这个连接时,就可以释放这个连接. TCP连接的建立是通过三次握手,而连接 ...

  3. TCP协议-长连接和短连接

    一 前言 TCP在真正开始进行数据传输之前,Server 和 Client 之间必须建立一个连接.当数据传输完成后,双方不再需要这个连接时,就可以释放这个连接. TCP连接的建立是通过三次握手,而连接 ...

  4. django oracle数据库配置,django连接oracle时setting 配置方法

    下一步是将新创建的应用程序与项目相关联.为此,您需要编辑 myproj 文件夹中的 settings.py 文件,将字符串"myproj.myapp"追加到 INSTALLED_A ...

  5. thinkphp长连接MySQL_ThinkPHP3.2.3---mysql+ajax实现长连接,实时监测数据库数据是否更新...

    实现目标 对数据库的数据更新进行监测,如果更新了数据就将数据全部显示出来,没有更新,则一直监测. 比如有一个服务端(浏览器),有很多客户端(浏览器),客户端提交了数据,服务端想要在不刷新浏览器的情况下 ...

  6. 应用服务器与数据库之间是长连接,要接收多个 tcp 长连接不断发送的数据并存储,哪些数据库或数据存储方案比较合适?...

    在服务器建立服务端,与多个 tcp 连接保持长连接,服务端会根据客户端发送的 token 验证确定是否保持长连接建立"session"缓存, 在某个状态开启时(我称为存储状态),要 ...

  7. php mysql持久连接是怎样的_怎样使PHP与MySQL数据库进行持久连接

    本篇文章是关于介绍PHP与MySQL数据库进行持久连接的具体操作步骤,有需要的朋友可以了解一下,希望能对你有帮助. 数据库持久连接: 1.持久的数据库连接是指在脚本结束运行时不关闭的连接.当收到一个持 ...

  8. php 长连接心跳_支持gRPC长链接,深度解读Nacos2.0架构设计及新模型

    作者 | 杨翊(席翁) Nacos PMC 来源|阿里巴巴云原生公众号 Nacos 简介 Nacos 在阿里巴巴起源于 2008 年五彩石项目,该项目完成了微服务拆分和业务中台建设,随着云计算和开源环 ...

  9. HTTP长连接和短连接以及推送服务原理(转)

    HTTP长连接和短连接以及推送服务原理 转自:http://blog.csdn.net/freewaywalker/article/details/50067757 HTTP长连接和短连接1 1. H ...

  10. HTTP长连接和短连接 + Websocket

    HTTP协议与TCP/IP协议的关系 HTTP的长连接和短连接本质上是TCP长连接和短连接.HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议.IP协议主要解决网络路由和寻址问题,T ...

最新文章

  1. java 计算两个日期之间的天数_Java日期时间API系列22-----Jdk8Month月份和DayOfWeek星期的计算。...
  2. You should rebuild using libgmp = 5 to avoid timing attack vulnerability.
  3. 阿里云产品搭建web应用梳理
  4. Kotlin难点解析:extension和this指针
  5. zoj-What day is that day?
  6. JPQL设置自增长、只读、文本类型等的注解
  7. 五分钟教你在Go-Bigger中设计自己的游戏AI智能体
  8. 深度思考|TCP协议存在那些缺陷?
  9. 5G iPhone,再等一年,有三款!
  10. 随机抽取题目程序java_分析并实现一个简单的抽人程序
  11. [Ruby on Rails系列]3、初试Rails:使用Rails开发第一个Web程序
  12. 双水泵轮换工作原理图_周宁气压给水设备控制柜原理图
  13. 【Todo】【读书笔记】Linux高性能服务器编程
  14. Win10电脑如何找出隐藏的文件
  15. [ROS-Beginner]1.安装与配置ROS环境
  16. netcore里使用jwt做登陆授权
  17. golang-亚马逊s3上传图片文件
  18. rdl报表 mysql_SSRS报表服务随笔(rdl报表服务)-报表参数
  19. 快速实现B站(B ili b ili)手机缓存m4s文件转mp4(批量升级版)
  20. android 没有指南针,Android指南针指向我的位置,而不是北部

热门文章

  1. Hash和Bloom Filter
  2. 【原】数据库排序规则导致的问题
  3. 解决iPhone、iPad 或 iPod touch 无法连接Wi-Fi网络问题
  4. JS实现单源点最短路径、动态规划分段图算法
  5. Laravel 获取执行的sql语句
  6. Linux——搭建PHP开发环境第四步:composer
  7. 【赏析】15个非常棒的使用CSS3的设计组合
  8. [RHEL5企业级Linux服务攻略]--第8季 Iptables服务全攻略之实战配置
  9. poj 1511 Invitation Cards spfa 基础题!!虽然我做的比较坎坷!!可以练手啊!!
  10. poj 2263 Heavy Cargo floyd基础,就是输入的时候处理字符串纠结一点!!!!