在整个Express应用程序中实现单个数据库池的正确方法

时间:2019-05-03 13:52:17

标签: javascript node.js express connection-pooling mysqljs

注意:此问题主要是关于节点中的单例对象,而不是数据库池。

我正在使用用于数据库连接的mysqljs节点模块构建一个expressjs应用程序。我想创建一个可在整个应用程序中重复使用的单个池对象(用于不同的模型等)。我想知道在快速应用中使用单个对象实例的正确方法是什么

我已经看到很多例子,人们可以像这样创建db.js文件或pool.js文件,并在需要的地方使用它

// db.js
var mysql = require('mysql');
var pool;
module.exports = {
    getPool: function () {
      if (pool) return pool;
      pool = mysql.createPool(dbConfig);
      return pool;
    }
};

// app.js
var pool = require('pool').getPool();
pool.query('SELECT * FROM users');

但是我觉得这仍然不是正确的方法,因为您每次需要对象时都依赖于nodejs缓存来返回相同的实例。如果该节点最终两次加载了代码,则最终会有两个池,例如

const poolA = require('./pool').getPool();
const poolB = require('./POOL').getPool(); // resolves to same file but node will not get result from cache

console.log(poolA === poolB); // false

从我读过的大多数内容来看,由于这种行为,通常不建议在节点应用程序中使用单例对象,但这似乎是快速应用程序的常见用例。所以我想知道人们如何在应用程序的生命周期内创建单个池?

注意:我目前正在做的事是在应用程序根目录中实例化池,然后将实例作为构造函数的参数传递,但我也不喜欢

1 个答案:

答案 0 :(得分:0)

简短答案

我在您的代码中看不到任何问题。

长期回答

此解决方案是假设您实际上没有名为POOL.js的文件,且文件的代码完全相同。

下面的require解析为与pool.js相同的文件,因为您使用的是启用了case-insensitivity的文件系统。例如NTFSAPFS

const poolB = require('./POOL').getPool();

如果您使用case sensitive之类的ext4文件系统,则会出错。

Error: Cannot find module './POOL'

内部node根据您提供的文件路径名缓存文件。来自source

const relativeResolveCache = Object.create(null);

relResolveCacheIdentifier = `${parent.path}\x00${request}`;
const filename = relativeResolveCache[relResolveCacheIdentifier];

if (filename !== undefined)
...

由于JavaScriptcase-sensitive,所以具有属性(简单地)cachepool的对象(上面的POOL)将是不同的并完全引用2种不同的对象引用。

结论

当心带有文件名或标识符名的陷阱