node mysql单例_NodeJS 中的模块是单例的吗?

笔者之前在使用require导入模块时,特别是在导入有状态的模块时,笔者会考虑其是否在多次导入情况下依然保持单例特性,或者说对于同一个文件在不同路径下导入时,是否能够识别为一致?本文即是对该特性进行解析。

12f304f8f21a5d72297e05998c29ec5a.png

NodeJS的模块默认情况下是单例性质的,不过其并不能保证如我们编程时设想的那样一定是单例,根据NodeJS的官方文档中描述,某个模块导入是否为单例受以下两个因素的影响:

Node 模块的缓存机制是大小写敏感的,譬如如果你require('/foo')与require('/FOO')会返回两个不同的对象,尽管你的foo与FOO是完全相同的文件。

模块是基于其被解析得到的文件名进行缓存的,鉴于不同的模块会依赖于其被调用的路径进行缓存鉴别,因此并不能保证你使用require('foo')会永远返回相同的对象,可能会根据不同的文件路径得到不同的对象。

f4241441d8432567034145572b6f46b1.gif

创建新的NodeJS模块

根据NodeJS文档所述,文件和模块是一一对应的关系。这个也是解释上文提及的模块缓存机制的基础,我们首先创建一个简单的模块:

// counter.js

let value = 0

module.exports = {

increment: () => value++,

get: () => value,

}

在counter.js中我们创建了某个私有变量,并且只能通过公共的increment与get方法进行操作。在应用中我们可以如下方法使用该模块:

// app.js

const counter = require(‘./counter.js’)

counter.increment()

counter.increment()

console.log(counter.get()) // prints 2

console.log(counter.value) // prints undefined as value is private

Module Caching

NodeJS会在第一次导入某个模块之后将该模块进行缓存,在官方文档中有如下描述:

Every call to require(‘foo’) will get exactly the same object returned, if it would resolve to the same file.

我们也可以通过如下简单的例子来验证这句话:

// app-singleton.js

const counter1 = require(‘./counter.js’)

const counter2 = require(‘./counter.js’)

counter1.increment()

counter1.increment()

counter2.increment()

console.log(counter1.get()) // prints 3

console.log(counter2.get()) // also prints 3

可以看出尽管我们两次导入了该模块,但是还是指向了同一个对象。不过并不是每次我们导入同一个模块时,都会得到相同的对象。在NodeJS中,模块对象有个内置的方法:Module._resolveFilename(),其负责寻找require中合适的模块,在找到正确的文件之后,会根据其文件名作为缓存的键名。官方的搜索算法伪代码为:

require(X) from module at path Y

1. If X is a core module,

a. return the core module

b. STOP

2. If X begins with './' or '/' or '../'

a. LOAD_AS_FILE(Y + X)

1. If X is a file, load X as JavaScript text. STOP

2. If X.js is a file, load X.js as JavaScript text. STOP

3...

4...

b. LOAD_AS_DIRECTORY(Y + X)

1. If X/package.json is a file,

a. Parse X/package.json, and look for "main" field.

b. let M = X + (json main field)

c. LOAD_AS_FILE(M)

2. If X/index.js is a file, load X/index.js as JS text. STOP

3...

4...

3. LOAD_NODE_MODULES(X, dirname(Y))

4. THROW "not found"

简单来说,加载的逻辑或者说优先级为:

优先判断是不是核心模块

如果不是核心模块则搜索node_modules

否则在相对路径中进行搜索

解析之后的文件名可以根据module对象或得到:

// counter-debug.js

console.log(module.filename) // prints absolute path to counter.js

console.log(__filename) // prints same as above

// i get: "/Users/laz/repos/medium/modules/counter-debug.js"

let value = 0

module.exports = {

increment: () => value++,

get: () => value,

在上述的例子中我们可以看出,解析得到的文件名即使被加载模块的绝对路径。而根据文件与模块一一映射的原则,我们可以得出下面两个会破坏模块导入单例性的特例。

Case Sensitivity

在大小写敏感的文件系统中或者操作系统中,不同的解析之后的文件可能会指向相同的文件,但是其缓存键名会不一致,即不同的导入会生成不同的对象。

// app-no-singleton-1.js

const counter1 = require('./counter.js')

const counter2 = require('./COUNTER.js')

counter1.increment()

console.log(counter1.get()) // prints 1

console.log(counter2.get()) // prints 0, not same object as counter1

/*

We have two different resolved filenames:

- “Users/laz/repos/medium/modules/counter.js”

- “Users/laz/repos/medium/modules/COUNTER.js”

*/

在上面的例子中,我们分别用counter、COUNTER这仅仅是大小写不同的方式导入相同的某个文件,如果是在某个大小写敏感的系统中,譬如UBUNTU中会直接抛出异常:

f54572a1eed50e938a184ddeb1672f0a.png

解析为不同的文件名

当我们使用require(x)并且x不属于核心模块时,其会自动搜索node_modules文件夹。而在npm3之前,项目会以嵌套的方式安装依赖。因此当我们的项目依赖module-a与module-b,并且module-a与module-b也相互依赖时,其会生成如下文件路径格式:

// npm2 installed dependencies in nested way

app.js

package.json

node_modules/

|---module-a/index.js

|---module-b/index.js

|---node_modules

|---module-a/index.js

这样的话,我们对于同一个模块就有两个副本,那当我们在应用中导入module-a时,岂会载入如下文件:

// app.js

const moduleA = require(‘module-a’)

loads: “/node_modules/module-a/index.js”

而从module-b中载入module-a时,其载入的是如下文件:

// /node_modules/module-b/index.js

const moduleA = require(‘module-a’)

loads “/node_modules/module-b/node_modules/module-a/index.js”

不过在npm3之后,其以扁平化方式进行文件加载,其文件目录结构如下所示:

// npm3 flattens secondary dependencies by installing in same folder

app.js

package.json

node_modules/

|---module-a/index.js

|---module-b/index.js

不过此时就存在另一个场景,即我们应用本身依赖module-a@v1.1与module-b,而module-b又依赖于module-a@v1.2,在这种情况下还是会采用类似于npm3之前的嵌套式目录结构。这样的话对于module-a一样会产生不同的对象,不过此时本身就是不同的文件了,因此相互之间不会产生冲突。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的第一个问题是关于 node.js 和 MySQL 插入语句的语法错误提示,是吗? 首先,你需要确保你的 MySQL 语句的语法是正确的。MySQL 插入语句的基本语法如下: ``` INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` 其,`table_name` 是你要插入数据的表的名称,`column1, column2, column3` 是你要插入的列的名称,`value1, value2, value3` 是你要插入的值。 在 node.js ,你可以使用 `mysql` 模块来连接和操作 MySQL 数据库。下面是一个示例代码,演示如何使用 `mysql` 模块来插入数据到 MySQL 数据库: ```javascript const mysql = require('mysql'); const connection = mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'mydatabase' }); connection.connect((err) => { if (err) throw err; console.log('Connected!'); const sql = "INSERT INTO customers (name, address) VALUES ('John Doe', 'Highway 71')"; connection.query(sql, (err, result) => { if (err) throw err; console.log('1 record inserted'); connection.end(); }); }); ``` 在上面的代码,我们创建了一个 `mysql` 连接对象 `connection`,并在连接成功后,使用 `connection.query()` 方法来执行 MySQL 插入语句。 如果你使用类似上面的代码来执行 MySQL 插入语句,但是仍然遇到语法错误提示,那么你需要检查你的 MySQL 语句是否正确。你可以尝试在 MySQL 命令行执行你的 MySQL 语句,以确保它没有语法错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值