Node.js中的ORM
ORM2是一款基于Node.js实现的ORM框架,名字相当的霸气,算是同类框架中非常出色的一款,具体介绍请猛击:https://github.com/dresende/node-orm2
刚接触Node.js + MySQL,在引入项目之初,受Asp.Net经验的影响,产生了许多不小的麻烦。下面是我定义的一个BaseProvider,作为所有DB Provider的父类,提供了一些公共的方法和属性。
function BaseProvider() {
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);
}
});
};
getProviderModel 相当于获得一个Model,具有CRUD的功能,简化我们写SQL语句的繁琐过程,下面是一个具体子类的实现。
function Dungeon() {
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();
在阅读ORM2的源码后,我发现了一个严重的问题,该方法用于连接,返回一个名为db的ORM对象,这个对象的职责是维护Nodejs到具体DB的连接信息、各种配置、连接池、缓存、Model等,而非ADO.Net中单纯的Connection,下面是ORM. Connect的部分代码。
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 = new ORM(proto, driver, settings);
driver.connect(function (err) {
if (typeof cb === "function") {
if (err) {
return cb(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);
}
return ORM_Error(ex, cb);
}
return db;
};
而我常用define方法,就是在上面的那个db中的models数组中push一个对象而已。
ORM.prototype.define = function (name, properties, opts) {
var i;
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] = new Model({
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];
};
ORM2在connect时就把mysql的连接池自己维护起来了,存在一个变量中,所以Provider的每一次操作都会ORM.connect,返回的db作为一个局部变量用完就丢弃,维护的连接池也没有保存,造成连接数太多,从而产生many connection error,下图是mysql统计的数据,丢失的连接数达1000多。

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

我在系统启动时创建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个连接满足执行需求。

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

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

Node.js中的ORM的更多相关文章
- 在node.js中,使用基于ORM架构的Sequelize,操作mysql数据库之增删改查
Sequelize是一个基于promise的关系型数据库ORM框架,这个库完全采用JavaScript开发并且能够用在Node.JS环境中,易于使用,支持多SQL方言(dialect),.它当前支持M ...
- [转]在node.js中,使用基于ORM架构的Sequelize,操作mysql数据库之增删改查
本文转自:https://www.cnblogs.com/kongxianghai/p/5582661.html Sequelize是一个基于promise的关系型数据库ORM框架,这个库完全采用Ja ...
- 如何在Node.js中合并两个复杂对象
通常情况下,在Node.js中我们可以通过underscore的extend或者lodash的merge来合并两个对象,但是对于像下面这种复杂的对象,要如何来应对呢? 例如我有以下两个object: ...
- Node.js中的Session,不要觉得简单哦。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博客地址为http://www.cnblogs.com/jasonnode/ .学习网站上有对应 ...
- Node.js 中MongoDB的基本接口操作
Node.js 中MongoDB的基本接口操作 连接数据库 安装mongodb模块 导入mongodb模块 调用connect方法 文档的增删改查操作 插入文档 方法: db.collection(& ...
- 在node.js中使用COOKIE
node.js中如何向客户端发送COOKIE呢?有如下两个方案: 一.使用response.writeHead,代码示例: //设置过期时间为一分钟 var today = new Date(); v ...
- 初步揭秘node.js中的事件
当你学习node.js的时候,Events是一个非常重要的需要理解的事情.非常多的Node对象触发事件,你能在文档API中找到很多例子.但是关于如何写自己的事件和监听,你可能还不太清楚.如果你不了解, ...
- Node.js权威指南 (10) - Node.js中的错误处理与断言处理
10.1 使用domain模块处理错误 / 272 10.1.1 domain模块概述 / 272 10.1.2 创建并使用Domain对象 / 274 10.1.3 隐式绑定与显式绑定 / 276 ...
- Node.js中的URL
Node.js中的URL 什么是URL URL是Uniform Location Resource的缩写,翻译为"统一资源定位符",也就是描述资源位置的固定表示方法.被URL描述的 ...
随机推荐
- linux服务器初步印象,远程连接mysql数据库,传输文件,启动/关闭tomcat命令
1.连接服务器数据库,以Navicat连接mysql为例 1.1 常规 新建连接,连接名,主机名或ip地址:127.0.0.1 端口:3306用户名:(服务器端)root密码:(服务器端)pwd 1. ...
- codeforces #309 div1 C
首先我们会发现所有的人构成了一个图 定义相爱为 在一个集合里 定义相恨为 不在一个集合里 很容易发现满足条件的图一定是一个二分图 那么分类讨论如下: 1.如果出现不合法 答案为0 2.如果不是一个二分 ...
- [itint5]支持删除的后继查询
http://www.itint5.com/oj/#49 这一题一开始想到是用HashSet+链表来做,链表记录prev和next.这样也可以,后来看到都是连续的整数,而且交流了一下觉得可以用类似并查 ...
- web.xml的说明
<!--DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. Copyright 2000-2007 Sun Microsystems ...
- foreman1.3安装
一.环境: centos 6.3 64bit 二.安装yum源: rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release ...
- 【HDOJ】4729 An Easy Problem for Elfness
其实是求树上的路径间的数据第K大的题目.果断主席树 + LCA.初始流量是这条路径上的最小值.若a<=b,显然直接为s->t建立pipe可以使流量最优:否则,对[0, 10**4]二分得到 ...
- Android开发之实用小知识点汇总-1
1.去掉android屏幕中的actionbar: this.requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏 //这个是全屏幕显示的代码 ...
- ubuntu终端颜色配置
对于刚接触ubuntu的同学们,打开终端(ctrl+alt+T),会发现里面都是一个颜色,不管是用户名.主机名还是命令都是白色,当然,用 ls 列出文件的时候是会多一种颜色的.即使这样,对开发人员来说 ...
- 「拒絕存取路徑 'C:\Users\xxx\AppData\Local\Temp\Temporary ASP.NET Files\apname\3a1b3704\f7fc6d0c\App_Code.l8ieogii.0.cs」的錯誤!
修改web.config中的system.web->compilation tag中,多加入tempDirectory="可存取的目錄" <system.web&g ...
- UVa 540 (团体队列) Team Queue
题意: 每个人都属于一个团体,在排队的时候,如果他所在的团体有人在队伍中,则他会站到这个团体的最后.否则站到整个队伍的队尾. 输出每次出队的人的编号. 分析: 容易看出,长队中,在同一个团体的人是排在 ...