`

mongoose Connection类

 
阅读更多

Connection是数据库连接对象,专门负责连接的。node-mongodb-native是数据库驱动,

driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native'
Collection  = require(driver + '/collection')

 如果没有设置全局的驱动路径,它是会提供一个自带的驱动的。Connection里面维护了一个驱动的连接,最终指向的是node.js里的一个mongodb模块,是它去真正跟mongodb数据库服务器建立联系的。

对于整个Connection类来说,主要功能就是打开连接和关闭连接,打开连接的时候会获取一个db对象,这个对象就是后面用来操作的对象。

 

打开相关的诸多方法:

Connection.prototype.open = function (host, database, port, options, callback) {
  var self = this
    , parsed
    , uri;

  if ('string' === typeof database) {
    switch (arguments.length) {
      case 2:
        port = 27017;
      case 3:
        switch (typeof port) {
          case 'function':
            callback = port, port = 27017;
            break;
          case 'object':
            options = port, port = 27017;
            break;
        }
        break;
      case 4:
        if ('function' === typeof options)
          callback = options, options = {};
    }
  } else {
    switch (typeof database) {
      case 'function':
        callback = database, database = undefined;
        break;
      case 'object':
        options = database;
        database = undefined;
        callback = port;
        break;
    }

    if (!rgxProtocol.test(host)) {
      host = 'mongodb://' + host;
    }

    try {
      parsed = muri(host);
    } catch (err) {
      this.error(err, callback);
      return this;
    }

    database = parsed.db;
    host = parsed.hosts[0].host || parsed.hosts[0].ipc;
    port = parsed.hosts[0].port || 27017;
  }

  this.options = this.parseOptions(options, parsed && parsed.options);

  // make sure we can open
  if (STATES.disconnected !== this.readyState) {
    var err = new Error('Trying to open unclosed connection.');
    err.state = this.readyState;
    this.error(err, callback);
    return this;
  }

  if (!host) {
    this.error(new Error('Missing hostname.'), callback);
    return this;
  }

  if (!database) {
    this.error(new Error('Missing database name.'), callback);
    return this;
  }

  // authentication
  if (options && options.user && options.pass) {
    this.user = options.user;
    this.pass = options.pass;

  } else if (parsed && parsed.auth) {
    this.user = parsed.auth.user;
    this.pass = parsed.auth.pass;

  // Check hostname for user/pass
  } else if (/@/.test(host) && /:/.test(host.split('@')[0])) {
    host = host.split('@');
    var auth = host.shift().split(':');
    host = host.pop();
    this.user = auth[0];
    this.pass = auth[1];

  } else {
    this.user = this.pass = undefined;
  }

  this.name = database;
  this.host = host;
  this.port = port;

  this._open(callback);
  return this;
};

 这个方法就是Mongoose在createConnection的时候调用的方法,这个方法只是处理和验证参数的合法性,然后调用this._open(callback);方法。由于node.js缺乏多态机制,所以在// make sure we can open注释之上的部分都是相当于模拟多态的效果。而// make sure we can open注释下面的部分主要是验证参数的合法性,格式上的合法。

Connection.prototype.openSet = function (uris, database, options, callback) {
  if (!rgxProtocol.test(uris)) {
    uris = 'mongodb://' + uris;
  }

  var self = this;

  switch (arguments.length) {
    case 3:
      switch (typeof database) {
        case 'string':
          this.name = database;
          break;
        case 'object':
          callback = options;
          options = database;
          database = null;
          break;
      }

      if ('function' === typeof options) {
        callback = options;
        options = {};
      }
      break;
    case 2:
      switch (typeof database) {
        case 'string':
          this.name = database;
          break;
        case 'function':
          callback = database, database = null;
          break;
        case 'object':
          options = database, database = null;
          break;
      }
  }

  var parsed;
  try {
    parsed = muri(uris);
  } catch (err) {
    this.error(err, callback);
    return this;
  }

  if (!this.name) {
    this.name = parsed.db;
  }

  this.hosts = parsed.hosts;
  this.options = this.parseOptions(options, parsed && parsed.options);
  this.replica = true;

  if (!this.name) {
    this.error(new Error('No database name provided for replica set'), callback);
    return this;
  }

  // authentication
  if (options && options.user && options.pass) {
    this.user = options.user;
    this.pass = options.pass;

  } else if (parsed && parsed.auth) {
    this.user = parsed.auth.user;
    this.pass = parsed.auth.pass;

  } else {
    this.user = this.pass = undefined;
  }

  this._open(callback);
  return this;
};

 openSet跟open方法等价,它的作用是连接到副本集,如果项目数据库是用分布式集群的方式部署,打开连接的方式应该是用这种。

Connection.prototype._open = function (callback) {
  this.readyState = STATES.connecting;
  this._closeCalled = false;

  var self = this;

  var method = this.replica
    ? 'doOpenSet'
    : 'doOpen';

  // open connection
  this[method](function (err) {
    if (err) {
      self.readyState = STATES.disconnected;
      if (self._hasOpened) {
        if (callback) callback(err);
      } else {
        self.error(err, callback);
      }
      return;
    }

    self.onOpen(callback);
  });
}

/**
 * Called when the connection is opened
 *
 * @api private
 */

Connection.prototype.onOpen = function (callback) {
  var self = this;

  function open (err) {
    if (err) {
      self.readyState = STATES.disconnected;
      if (self._hasOpened) {
        if (callback) callback(err);
      } else {
        self.error(err, callback);
      }
      return;
    }

    self.readyState = STATES.connected;

    // avoid having the collection subscribe to our event emitter
    // to prevent 0.3 warning
    for (var i in self.collections)
      self.collections[i].onOpen();

    callback && callback();
    self.emit('open');
  };

  // re-authenticate
  if (self.user && self.pass) {
    self.db.authenticate(self.user, self.pass, self.options.auth, open);
  }
  else
    open();
};

1.for (var i in self.collections):表明open的时候可以根据传入的参数打开多个连接。

2.self.collections[i].onOpen():最终打开连接的也不是它自己,而是用的mongodb模块,这里不在深究了,其实在用的时候更重要的是参数的作用和意义。

3.readyState:这个属性是用来描述连接的当前状态的,当状态改变的时候,它会触发响应的事件。这里要提醒的是,这个状态可以会多次改变,所以响应事件的方法得注意。

 

 

Connection.prototype.close = function (callback) {
  var self = this;
  this._closeCalled = true;

  switch (this.readyState){
    case 0: // disconnected
      callback && callback();
      break;

    case 1: // connected
      this.readyState = STATES.disconnecting;
      this.doClose(function(err){
        if (err){
          self.error(err, callback);
        } else {
          self.onClose();
          callback && callback();
        }
      });
      break;

    case 2: // connecting
      this.once('open', function(){
        self.close(callback);
      });
      break;

    case 3: // disconnecting
      if (!callback) break;
      this.once('close', function () {
        callback();
      });
      break;
  }

  return this;
};

Connection.prototype.onClose = function () {
  this.readyState = STATES.disconnected;

  // avoid having the collection subscribe to our event emitter
  // to prevent 0.3 warning
  for (var i in this.collections)
    this.collections[i].onClose();

  this.emit('close');
};

  关闭连接。

 

另外,Connection对象是也可以注册model的,这只能说是增加灵活性吧。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics