zoukankan      html  css  js  c++  java
  • mongodb数据库调试问题:‘db object already connecting, open cannot be called multiple times’

    在微博小系统的调试过程中:

      (1)登入登出可以正常显示,就是在注册的时候网络连接突然停止,但是用户名和密码已经存入数据库中,报错为:undefined is not a function

         错误主要指向Use.js中的一句话:mongodb.close();

         解决方案:因为mongodb版本高于1.3.0,所以认为mongodb.close()这个函数未定义而当做函数来用,直接把mongodb.close()这句话注释掉则系统可以正常注册运行;

    (2)注释掉mongodb.close()以后系统又出现mongodb经常会出现的错误db object already connecting, open cannot be called multiple times’

        nodejs是异步线程,无论如何,都要用到db.open(),但是每次打开数据库访问完毕后还得对应关闭书裤裤db.close();

        在上一步调试中注释掉关闭数据库,则数据库一直是处于打开状态,数据库还未关闭就在此打开则会出现db object already connecting, open cannot be called multiple times’的错误

        此时的解决方案:

          a:在数据库在此打开之前直接在前面加上一个mongodb.close()以确保每次数据库打开之前已经关闭数据库,经调试系统正常运行;

          b.从open and close 行为改为 open once and reuse anywhere。程序启动的时候db.open一次,每次http请求直接访问数据库,扔掉db.open/db.close这2个多余的操作

         原始的open + close方法:   

    var server_options={};
    var db_options={w:-1};
    
    var mongodb = require("mongodb"),
        mongoserver = new mongodb.Server('localhost', 27017,server_options ),
        db = new mongodb.Db('test', mongoserver, db_options);
    
    var http=require('http');
    
    var server=http.createServer(function(req,res){
        db.open(function(err,db){
            if(err)return console.error(err);
            console.log('* mongodb connected');
            db.collection('foo').save({test:1},function(err,result){
                res.end(JSON.stringify(result,null,2));
                db.close();
            });
        })
    
    });
    server.listen(8080,function(){
        console.log('server listen to %d',this.address().port);
    });
    setTimeout(function(){
        //http.get('http://localhost:8080',function(res){console.log('request ok')});
        //http.get('http://localhost:8080',function(res){console.log('request ok')});
    },2000);
    

      扔掉db.open/db.close这2个循环对应操作的方法,让其最开始就一直处于打开状态

    var server_options={'auto_reconnect':true,poolSize:5};
    var db_options={w:-1};
    
    var mongodb = require("mongodb"),
        mongoserver = new mongodb.Server('localhost', 27017,server_options ),
        db = new mongodb.Db('test', mongoserver, db_options);
    
    db.open(function(err,db){
        if(err)throw err;
        console.info('mongodb connected');
    });
    var http=require('http');
    
    var server=http.createServer(function(req,res){
        db.collection('foo').save({test:1},function(err,result){
            res.end(JSON.stringify(result,null,2));
        });
    
    });
    server.listen(8080,function(){
        console.log('server listen to %d',this.address().port);
    });
    setTimeout(function(){
        http.get('http://localhost:8080',function(res){console.log('request ok')});
        http.get('http://localhost:8080',function(res){console.log('request ok')});
    },2000); 

    这样改会引入潜在问题:当并发访问>5时,因为同时可用的底层数据库连接只有5,从而导致了阻塞。

    实际应用场景中,直接引用db对象并不是一个好主意。默认情况下,db的poolSize=5,意味着并发只有5, 要提高并发的话,把poolSize拉到10? 20? 50? 100? NO,我们需要的是能动态调整连接数的连接池,既能满足高峰期的连接数要求,也能在空闲期释放闲置的连接,而不是象mongodb的内置连接池那样保持固定连接数。怎么办?重新发明轮子吗?不,重用已有的连接池模块generic_pool,代码如下

    var http=require('http'),
        mongodb = require("mongodb"),
        poolModule = require('generic-pool');
    
    var pool = poolModule.Pool({
        name     : 'mongodb',
        create   : function(callback) {
            var server_options={'auto_reconnect':false,poolSize:1};
            var db_options={w:-1};
            var mongoserver = new mongodb.Server('localhost', 27017,server_options );
            var db=new mongodb.Db('test', mongoserver, db_options);
            db.open(function(err,db){
                if(err)return callback(err);
                callback(null,db);
            });
        },
        destroy  : function(db) { db.close(); },
        max      : 10,//根据应用的可能最高并发数设置
        idleTimeoutMillis : 30000,
        log : false 
    });
    
    var server=http.createServer(function(req,res){
        pool.acquire(function(err, db) {
            if (err) {
                res.statusCode=500;
                res.end(JSON.stringify(err,null,2));
            } else {
                db.collection('foo').save({test:1},function(err,result){
                    res.end(JSON.stringify(result,null,2));
                    pool.release(db);
                });
            }
        });
    });
    server.listen(8080,function(){
        console.log('server listen to %d',this.address().port);
    });
    setTimeout(function(){
        http.get('http://localhost:8080',function(res){console.log('request ok')});
        http.get('http://localhost:8080',function(res){console.log('request ok')});
    },2000);
    

      c.对于mongodb数据库有一个问题:刷新得太快,或者多个用户同时访问数据库,数据库没来得及关闭,db object already connecting, open cannot be called multiple times这个错误就会出现

         我们如果换成使用mongoose就不会出现这错误,因为对于mongoose而言,一旦连接好数据库,db就会处于open状态,不存在访问时要打开,然后又要关闭的规则,

     这是用mongodb的操作方法:

    User.get = function get(username, callback) {
      mongodb.open(function(err, db) {
        if (err) {
          return callback(err);
        }
        //读取 users 集合
        db.collection('users', function(err, collection) {
          if (err) {
            mongodb.close();
            return callback(err);
          }
          //查找 name 属性为 username 的文档
          collection.findOne({name: username}, function(err, doc) {
            mongodb.close();
            if (doc) callback (err, doc);
            else callback (err, null);
          });
        });
      });
    };
    

      这是用mongoose的操作方法

    User.get = function get(username, callback) {
      users.findOne({name:username}, function(err, doc){
        if (err) {
          return callback(err, null);
        }
        return callback(err, doc);
      });
    };
    

      

    以上a.b.c则为解决db object already connecting, open cannot be called multiple times’问题的三种方案总结

  • 相关阅读:
    拓展欧几里得
    使用BIOS进行键盘输入和磁盘读写
    直接定址表
    指令系统总结
    端口
    内中断
    标志寄存器
    call 和 ret 指令
    编写包含多个功能子程序的中断例程
    字符串的输入
  • 原文地址:https://www.cnblogs.com/zlz-ling/p/4139187.html
Copyright © 2011-2022 走看看