node.js mysql orm_Node.js中的ORM

ORM2是一款基于Node.js实现的ORM框架,名字相当的霸气,算是同类框架中非常出色的一款,具体介绍请猛击:https://github.com/dresende/node-orm2

刚接触Node.js + MySQL,在引入项目之初,受Asp.Net经验的影响,产生了许多不小的麻烦。下面是我定义的一个BaseProvider,作为所有DB Provider的父类,提供了一些公共的方法和属性。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

functionBaseProvider() {this.table_name ={};this.properties ={};this.opts ={};this.getProviderModel = function(callback) {

define(this.table_name, this.properties, this.opts, function(error, model) {

callback(error, model);

});

};

};var define = function(name, properties, opts, callback) {

ORM.connect(pomelo.app.get("mysql"), function(error, db) {if(error) {

logger.error(error);

callback(error);

}else{

db.settings.set("connection.pool", true);var model =db.define(name, properties, opts);

callback(null, model);

}

});

};

View Code

getProviderModel 相当于获得一个Model,具有CRUD的功能,简化我们写SQL语句的繁琐过程,下面是一个具体子类的实现。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

functionDungeon() {this.table_name = "dungeon_userdungeons";this.properties ={

dungeon_userdungeon_id: Number,

user_id: Number,

dungeon_id: String,

latest_scene_id: String,

status: Number,

create_datetime_utc: Date

};this.opts = {id: 'dungeon_userdungeon_id'};this.getUserCompleteDungeonIds = function(user_id, callback) {this.getProviderModel(function(error, model) {

model.aggregate(["dungeon_id"], {user_id: user_id, status: Dungeon.Status.Complete}).max("dungeon_id").groupBy("dungeon_id").get(function(error, userdungeons) {var dungeon_ids =[];

userdungeons.forEach(function(e) {

dungeon_ids.push(e.dungeon_id);

})

callback(error, dungeon_ids);

});

});

};

};

Dungeon.prototype= new BaseProvider();

View Code

在阅读ORM2的源码后,我发现了一个严重的问题,该方法用于连接,返回一个名为db的ORM对象,这个对象的职责是维护Nodejs到具体DB的连接信息、各种配置、连接池、缓存、Model等,而非ADO.Net中单纯的Connection,下面是ORM. Connect的部分代码。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

var connect = function() {try{var Driver = require("./Drivers/DML/" +proto).Driver;var settings = new Settings.Container(exports.settings.get('*'));var debug = extractOption(opts, "debug");var pool = extractOption(opts, "pool");var driver = new Driver(opts, null, {

debug: (debug!== null ? Boolean(debug) : settings.get("connection.debug")),

pool: (pool!== null ? Boolean(pool) : settings.get("connection.pool")),

settings: settings

});

db= newORM(proto, driver, settings);

driver.connect(function(err) {if (typeof cb === "function") {if(err) {returncb(err);

}else{return cb(null, db);

}

}

db.emit("connect", err, !err ? db : null);

});

}catch(ex) {if (ex.code === "MODULE_NOT_FOUND" || ex.message.indexOf('find module')) {return ORM_Error(ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "CONNECTION_PROTOCOL_NOT_SUPPORTED"), cb);

}returnORM_Error(ex, cb);

}returndb;

};

View Code

而我常用define方法,就是在上面的那个db中的models数组中push一个对象而已。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

ORM.prototype.define = function(name, properties, opts) {vari;

properties= properties ||{};

opts= opts ||{};for (i = 0; i < this.plugins.length; i++) {if (typeof this.plugins[i].beforeDefine === "function") {this.plugins[i].beforeDefine(name, properties, opts);

}

}this.models[name] = newModel({

db:this,

settings:this.settings,

driver_name:this.driver_name,

driver:this.driver,

table: opts.table|| opts.collection || ((this.settings.get("model.namePrefix") || "") +name),

properties: properties,

extension: opts.extension|| false,

indexes: opts.indexes||[],

cache: opts.hasOwnProperty("cache") ? opts.cache : this.settings.get("instance.cache"),

id: opts.id|| this.settings.get("properties.primary_key"),

autoSave: opts.hasOwnProperty("autoSave") ? opts.autoSave : this.settings.get("instance.autoSave"),

autoFetch: opts.hasOwnProperty("autoFetch") ? opts.autoFetch : this.settings.get("instance.autoFetch"),

autoFetchLimit: opts.autoFetchLimit|| this.settings.get("instance.autoFetchLimit"),

cascadeRemove: opts.hasOwnProperty("cascadeRemove") ? opts.cascadeRemove : this.settings.get("instance.cascadeRemove"),

hooks: opts.hooks||{},

methods: opts.methods||{},

validations: opts.validations||{}

});for (i = 0; i < this.plugins.length; i++) {if (typeof this.plugins[i].define === "function") {this.plugins[i].define(this.models[name], this);

}

}return this.models[name];

};

View Code

ORM2在connect时就把mysql的连接池自己维护起来了,存在一个变量中,所以Provider的每一次操作都会ORM.connect,返回的db作为一个局部变量用完就丢弃,维护的连接池也没有保存,造成连接数太多,从而产生many connection error,下图是mysql统计的数据,丢失的连接数达1000多。

7dc6a041ca05399c4983f43e535f6696.png

每次调用都是新的连接池。

dab008c2a08d3c09b4e400dec3076e91.png

我在系统启动时创建ORM的DB,存到BaseProvider的原型中。

ORM.connect(pomelo.app.get("mysql"), function(error, db) {

BaseProvider.prototype.db=db;

console.log("init connect~");

});

Define的时候直接访问缓存的db变量。

var define = function(name, properties, opts, callback) {var model =BaseProvider.prototype.db.define(name, properties, opts);

callback(null, model);

};

我并发执行6个操作,连接池会创建6个连接满足执行需求。

261ce2dc8834f7c81ed6143d1fb572fa.png

因为先前已经创建了6个连接,第二次执行的时候,则直接返回。

be1ca3f9f993239768483d2ecf807678.png

测试了一下午,连接池终于正常了。

e88217d5433a04e875a45cbbce94fe0c.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值