99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Django學(xué)習(xí)之?dāng)?shù)據(jù)庫(kù)的鏈接詳解

發(fā)布時(shí)間:2016-12-24 12:32  回復(fù):0  查看:2911   最后回復(fù):2016-12-24 12:32  

最近總會(huì)遇到 MySQL server has gone away 的報(bào)錯(cuò),然后就看了一下django數(shù)據(jù)庫(kù)連接這一塊。

  django數(shù)據(jù)庫(kù)連接

  ORM中數(shù)據(jù)庫(kù)連接用到的 connections ,從 django.db 模塊引入,屬于 ConnectionHandler 對(duì)象。

  # django.db.__init__.py

  # django ORM中用到的數(shù)據(jù)庫(kù)連接來(lái)源

  connections = ConnectionHandler()

  # 請(qǐng)求開(kāi)始之前重置所有連接def reset_queries(**kwargs):

  for conn in connections.all():

  conn.queries_log.clear()

  signals.request_started.connect(reset_queries)

  # 請(qǐng)求開(kāi)始結(jié)束之前遍歷所有已存在連接,關(guān)閉不可用的連接def close_old_connections(**kwargs):

  for conn in connections.all():

  conn.close_if_unusable_or_obsolete()

  signals.request_started.connect(close_old_connections)

  signals.request_finished.connect(close_old_connections)

  我理解的 ConnectionHandler 類是一個(gè)數(shù)據(jù)庫(kù)連接管理器,負(fù)責(zé)根據(jù)不同數(shù)據(jù)庫(kù)后端創(chuàng)建數(shù)據(jù)庫(kù)連接,保存連接,給應(yīng)用方提供連接,以及關(guān)閉所有連接。 這里通過(guò)django信號(hào)的方式,在請(qǐng)求開(kāi)始之前以及請(qǐng)求結(jié)束之后關(guān)閉失效數(shù)據(jù)庫(kù)連接。

  # django.db.utils.py

  class ConnectionHandler(object):

  def __init__(self, databases=None):

  # 獲取數(shù)據(jù)庫(kù)配置

  self._databases = databases

  # 從當(dāng)前線程變量獲取所有數(shù)據(jù)庫(kù)連接

  self._connections = local()

  # 獲取數(shù)據(jù)庫(kù)連接關(guān)鍵邏輯

  def __getitem__(self, alias):

  # 首先直接從當(dāng)前線程變量獲取

  if hasattr(self._connections, alias):

  return getattr(self._connections, alias)

  # 重新建立數(shù)據(jù)庫(kù)連接并寫(xiě)入當(dāng)前線程變量

  self.ensure_defaults(alias)

  self.prepare_test_settings(alias)

  db = self.databases[alias]

  backend = load_backend(db['ENGINE'])

  # django.db.backends.mysql.base.DatabaseWrapper

  conn = backend.DatabaseWrapper(db, alias)

  setattr(self._connections, alias, conn)

  return conn

  ConnectionHandler 中 _connections 表示當(dāng)前數(shù)據(jù)庫(kù)連接集合,是一個(gè) ThreadLocal 對(duì)象,是和線程綁定在一起的。在整個(gè)線程生命周期內(nèi), _connections 屬于全局變量,但是當(dāng)線程一旦關(guān)閉, _connections 也消失了。

  關(guān)鍵邏輯在于 __getitem__ 方法,當(dāng)通過(guò)別名獲取數(shù)據(jù)庫(kù)連接時(shí),首先從當(dāng)前線程變量中獲取連接,獲取不到就根據(jù)別名創(chuàng)建新的數(shù)據(jù)庫(kù)連接,并將連接寫(xiě)入 ThreadLocal 。

  通過(guò)CONN_MAX_AGE設(shè)置連接存活時(shí)間

  django 1.6 開(kāi)始支持持久數(shù)據(jù)庫(kù)連接,通過(guò)參數(shù) CONN_MAX_AGE 設(shè)置每個(gè)連接的最大存活時(shí)間。默認(rèn)值是0,設(shè)置為None表示無(wú)限制的持久連接。

  # django.db.backends.base.base.py

  class BaseDatabaseWrapper(object):

  def connect(self):

  self.in_atomic_block = False

  self.savepoint_ids = []

  self.needs_rollback = False

  # 根據(jù)CONN_MAX_AGE參數(shù)設(shè)置連接的關(guān)閉時(shí)間

  max_age = self.settings_dict['CONN_MAX_AGE']

  self.close_at = None if max_age is None else time.time() + max_age

  ... ...

  def close_if_unusable_or_obsolete(self):

  if self.connection is not None:

  if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:

  self.close()

  return

  # 發(fā)生異常,檢查連接是否可用,不可用關(guān)閉連接

  if self.errors_occurred:

  if self.is_usable():

  self.errors_occurred = False

  else:

  self.close()

  return

  # 設(shè)置了超時(shí)時(shí)間,并且連接超時(shí),關(guān)閉連接

  if self.close_at is not None and time.time() >= self.close_at:

  self.close()

  return

  數(shù)據(jù)庫(kù)連接在建立的時(shí)候會(huì)根據(jù) CONN_MAX_AGE 參數(shù)設(shè)置連接的 close_at 屬性,表示連接失效時(shí)間。再看上面:point_up_2: django.db.__init__.py 的代碼,通過(guò)信號(hào)方式,每次請(qǐng)求開(kāi)始以及結(jié)束的時(shí)候,會(huì)調(diào)用 close_if_unusable_or_obsolete 方法,判斷當(dāng)連接超時(shí)或者處在不可恢復(fù)狀態(tài)時(shí)則關(guān)閉連接。

  總結(jié)

  1. django的數(shù)據(jù)庫(kù)連接是保存到線程變量的數(shù)據(jù)庫(kù)連接是全局的,但只存在于當(dāng)前線程中,如果線程關(guān)閉,數(shù)據(jù)庫(kù)連接也不存在了。

  2. 可以通過(guò)CONN_MAX_AGE參數(shù)配置數(shù)據(jù)庫(kù)連接的存活時(shí)間即使設(shè)置了CONN_MAX_AGE參數(shù),也是在線程依然存活的情況下,數(shù)據(jù)庫(kù)連接能夠存活的時(shí)間。

  需要注意的兩點(diǎn)是:

  ·CONN_MAX_AGE 應(yīng)該小于數(shù)據(jù)庫(kù)本身的最大連接時(shí)間 wait_timeout ,否則應(yīng)用程序可能會(huì)獲取到連接超時(shí)的數(shù)據(jù)庫(kù)連接,這時(shí)會(huì)出現(xiàn) MySQL server has gone away 的報(bào)錯(cuò)。

  ·如果部署方式采用多線程,最大線程數(shù)不能大于最大數(shù)據(jù)庫(kù)連接數(shù)。另外,開(kāi)發(fā)模式下(runserver),由于每條請(qǐng)求都是創(chuàng)建一個(gè)新的 Thread ,就不要使用 CONN_MAX_AGE 參數(shù)了,這樣在老的請(qǐng)求線程中保存的數(shù)據(jù)庫(kù)連接根本不能復(fù)用。

來(lái)源:rainybowe

您還未登錄,請(qǐng)先登錄

熱門帖子

最新帖子

?