node MySQL buffer_nodejs中Buffer对象(一)

在JS中,基本就没有对而二进制处理的机制,那是因为在客户端JS中不需要操作数据库等信息,需要操作的一些数据也都是服务器端处理好的数据,所以也不需要JS对这些二进制数据进行操作,但是对于nodejs中,好歹也是可以操作数据库的了,也属于服务器端语言的一种了,那么就必须对这些数据进行操作了。

Buffer类

因为Nodejs也只是属于JS的,是没有操作二进制方法的,那么Nodejs只能自己去实现该方法,于是就有了Buffer类,该类是用来创建一个专门存放二进制数据的缓存区,并提供一些方法用于对这缓存区的数据进行处理的API接口。

Buffer类实例化

Buffer类是一个可以在任何模块中被利用的全局类,不需要为该类的使用而加载任何模块,可以直接使用new关键字创建该类的实例对象,Buffer类实例化有三种不同的方式,下面就结合源代码分别对这三种方法进行一个解释说明:

1:传入size大小

把缓存区大小(以字节为单位)指定为构造函数的参数,生成一段内存区间。方式为:

var buf = new Buffer(size);

上述实例化的Buffer对象,有一个length=size的属性,表示缓存区的大小。在nodejs的REPL模式下,可以看下:

C:\nodejs>node

> buf = new Buffer(10);

>buf.length

10

其实该方法,就和我们在C语言中,创建一个大小为10的数组,数组内元素的值没有指定,这个时候,其内的值,就是一些随机的数据。

相比于JS,JS就更有规律,如果在前端创建一个长度为10的数组,那么数组的值都是undefined的值。

arr = new Array(10); //[undefined × 10]

arr.length; //10

arr[0]; //undefined

arr[1]; //undefined

OK,该种实例化方法,只是分配了一段内存区间,并没有赋值,如果先不赋值就直接操作,那么取到的值会比较随机,需要注意。

<2>

使用一个数组为参数进行实例化Buffer对象,用法如下:

var buf = new Buffer(array);

看在REPL模式下的执行结果:

>buf = new Buffer([1,2,3]);

>buf.length

3

>buf[1]

2

这个应该是我们比较习惯的一种写法了吧,相较于前端中的字面量创建数组的模式了:

var aa = [1,2,3];

var bb = new Array(1,2,3);

这个就没有什么好说的了。OK,继续最后一种创建方式。

3:字符串方式

参数为一个字符串的形式来初始化缓存区。方法如下:

var buf = new Buffer(str,[encoding]);

在这种形式的实例化Buffer时,使用两个参数:

第一个参数为必须制定的参数,用于初始化缓存区的字符串。

第二个参数用于指定字符串编码格式。默认格式为:“utf8”。

既然有编码方式,那么就会出现的一个问题,就是不同的编码方式,最后得到的数据中,内存区的大小时不同的。当前支持的一些编码方式有:“ascii”,“utf8”,“uft16le”,“ucs2”,“base64”,“binary”,“hex”。

看下在REPL模式下的执行结果:

//编码方式utf8

>buf = new Buffer("您好");

>buf.length

6

//编码方式utf16le

>buf = new Buffer("您好","utf16le");

>buf.length

4

不同的编码方式,生成的内存区间是不同的。

OK,使用方法说完了,那么接下来,就可以看下,在Nodejs中,源码中,是如何实现该构造函数的,从根本上理解一下,为何会有着三种实例化的方式。

Buffer构造函数源码分析

源码地址取自github项目:buffer.js;

//下面这些是在Buffer构造函数中使用到的一些基本的方法:

//smalloc为内存操作的对象

var smalloc = process.binding('smalloc');

//util为工具函数,包含一些基本的操作方法

var util = require('util');

//alloc对象用于生成一段内存的方法

var alloc = smalloc.alloc;

//truncate类似于一个查找方法,比如在数据库中根据一定的条件查表。

var truncate = smalloc.truncate;

//我的理解,这个sliceOnto是属于合并拼接内存区间所用

var sliceOnto = smalloc.sliceOnto;

//kMaxLength为生成内存区间的最大容量

var kMaxLength = smalloc.kMaxLength;

//pollSize表示自定义的一个值

Buffer.poolSize = 8 * 1024;

var poolSize, poolOffset, allocPool;

//定义的三个全局变量,也算是闭包内的私有变量

//上述的含义,是我再读源码时,按照当时的逻辑理解的意思,还没有去看相关部分的源码,所以,如果有任何疑问,请指教。

//createPool用于生成一个内存区间的,并把生成的内存区间存入allocPool

function createPool() {

poolSize = Buffer.poolSize;

allocPool = alloc({}, poolSize);

//allocPool保存生成的一段大小为poolSize的内存区间

poolOffset = 0;

//在生成的内存中使用位置的偏移量,用于保存当前内存区间的使用量,

//防止被后面的数据覆盖掉。

}

createPool();

//先生成一段供使用

//下述构造函数中,英文注释是源码中的注释,中文是我的理解注释。

function Buffer(subject, encoding) {

if (!util.isBuffer(this)){

//如果忘记使用new ,则重定义

return new Buffer(subject, encoding);

}

if (util.isNumber(subject)) {

//这里就是我们前面第一种实例化的源代码逻辑部分。

//如果第一个参数是一个数字,那么把该数字,定义为数组的长度

this.length = +subject;

} else if (util.isString(subject)) {

//实例化时,第三种实例化源码逻辑处理

//如果第一个参数是字符串

if (!util.isString(encoding) || encoding.length === 0){

//第二个参数不是字符串,则把第二个默认为utf8的编码

encoding = 'utf8';

}

//按照规定的编码方式,计算字符串的长度,并定义为在数组的长度

this.length = Buffer.byteLength(subject, encoding);

// Handle Arrays, Buffers, Uint8Arrays or JSON.

} else if (util.isObject(subject)) {

//构造函数第二种实例化处理逻辑

//如果第一个参数是一个对象

if (subject.type === 'Buffer' && util.isArray(subject.data)){

//如果第一个参数是buffer类型或者array类型,则直接处理

subject = subject.data;

}

//定义数组的长度

this.length = +subject.length;

} else {

//否则,抛出一个错误,第一个参数的类型,

//必须是固定的四种类型,其他类型是不被支持的。

throw new TypeError('must start with number, buffer, array or string');

}

//判断数组长度,是否超出最大长度,也就是数组时否溢出。

if (this.length > kMaxLength) {

//如果当前的buffer数组,过长,则抛出一个“范围异常”

throw new RangeError('Attempt to allocate Buffer larger than maximum ' +

'size: 0x' + kMaxLength.toString(16) + ' bytes');

}

//判断当前数组的长度是否小于0,如果是,则置为0

if (this.length < 0)

this.length = 0;

else

this.length >>>= 0; // Coerce to uint32.

//无符号右移,变化为数字的方法

this.parent = undefined;

if (this.length <= (Buffer.poolSize >>> 1) && this.length > 0) {

//在判断是否需要重新分配内存空间,不需要生成的话,则执行该部分逻辑

//如果需要生成的内存buffer的大小,占生成内存区间大小的一半之上的话

//则重新分配一整段的内存区间,存放该数据

if (this.length > poolSize - poolOffset){

//需要重新分配内存区间

createPool();

}

//parent表示,当前生成的buffer数组,是属于那一段内存区间的。

//allocPool表示上次生成的一段内存区间,或者前面刚刚生成的内存区间。

this.parent = sliceOnto(allocPool,

this,

poolOffset,

poolOffset + this.length);

//更新内存区间已使用的值,下次再有新的Buffer创建时,从该偏移继续保存数据

poolOffset += this.length;

// Ensure aligned slices

//没有看出来,这个是在干嘛?

//按我的感觉,应该是为了规范一下poolOffset的值,使得数据可以保存的更有规律

if (poolOffset & 0x7) {

poolOffset |= 0x7;

poolOffset++;

}

} else {

//给该数据,生成一个单独的静态内存区间,保存数据

alloc(this, this.length);

}

if (util.isNumber(subject)) {

//如果第一个参数是数字,那么这里就可以结束了。

return;

}

if (util.isString(subject)) {

// In the case of base64 it's possible that the size of the buffer

// allocated was slightly too large. In this case we need to rewrite

// the length to the actual length written.

var len = this.write(subject, encoding);

//调用buffer对象的write方法,write方法,后面再看~

// Buffer was truncated after decode, realloc internal ExternalArray

//如果当前的第一个参数是字符串,那么就把该字符串根据encoding的类型,写入到this的buffer对象上去

//

if (len !== this.length) {

//如果是字符串,在不同的编码下,字符串保存的数据大小时有区别的

//所以,这里对该部分,进行单独的特殊处理。

var prevLen = this.length;

//保存当前buffer的长度

this.length = len;

//更新到最新的长度。

truncate(this, this.length);

//更新该buffer数组

// Only need to readjust the poolOffset if the allocation is a slice.

if (this.parent != undefined)

poolOffset -= (prevLen - len);

//更新内存区间中poolOffset的位置,防止下次Buffer实例化时,

//把该部分数据给覆盖掉。

}

} else if (util.isBuffer(subject)) {

//第二种和第三种构造函数使用时,初始化数据到buffer对象中去。

//如果当前对象为Buffer对象,

//则把subject对象上的数据,保存到this对象上

subject.copy(this, 0, 0, this.length);

} else if (util.isNumber(subject.length) || util.isArray(subject)) {

// Really crappy way to handle Uint8Arrays, but V8 doesn't give a simple

// way to access the data from the C++ API.

//如果subject是数组的话,则~~使用数组赋值

for (var i = 0; i< this.length; i++)

this[i] = subject[i];

}

//构造函数,返回this对象,即一个新的buffer对象

}

总结

看着源码学习新的东西,虽然过程会很慢,但可以学的到更多,也能有更深层次的理解。

好的,你的第一个问题是关于 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、付费专栏及课程。

余额充值