0%

Nodejs使用MySQL 4.1的问题解决

数据库连接

如果使用old authentication方式连接4.1版本之前的mysql,sequelizemysql2无法通过认证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{ Error: Access denied for user: '@127.0.0.x' (Using password: NO)
at Packet.asError (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/packets/packet.js:714:13)
at ClientHandshake.Command.execute (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/commands/command.js:28:22)
at Connection.handlePacket (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/connection.js:513:28)
at PacketParser.onPacket (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/connection.js:81:16)
at PacketParser.executeStart (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/packet_parser.js:76:14)
at Socket.<anonymous> (/home/claude/Workspace/packages/sql/node_modules/mysql2/lib/connection.js:89:29)
at Socket.emit (events.js:182:13)
at addChunk (_stream_readable.js:283:12)
at readableAddChunk (_stream_readable.js:264:11)
at Socket.Readable.push (_stream_readable.js:219:10)
at TCP.onread (net.js:639:20)
code: 'ER_ACCESS_DENIED_ERROR',
errno: 1045,
sqlState: '',
sqlMessage:
'Access denied for user: \'@127.0.0.x\' (Using password: NO)' }

处理倒不困难,在不能改动数据库的情况下,可以改用npm包mysql

编码转换

移动mas的接入文档有描述如下:

mysql使用ISO8859-1编码,往db接口写入数据时应先把编码格式转化为ISO8859-1…

上述编码实际为latin1,为早期mysql的默认编码。实际文档存在误导,未指出mas机的db接口是使用gbk编码写入的,因此将字符进行转化gbk再使用该接口即可,无需再将编码转为latin1

但如果想从数据库中读取,同事在创建连接时指定了charset=latin1获取到的中文是乱码。

这涉及到mysql如何用latin1存储中文的问题:latin1为0x00 to 0xFF范围的单字节编码(ASCII是它的子集),理论上单字节范围可以无损存储数据,任意编码均可以用字节流形式存储。

也就是说,mas机写入之前用的是gbk字节流,读取时直接用nodejs默认的utf8编码自然不行。那么怎样读出二进制数据呢?在npm mysql库的README中搜索buffer字样,找到了如下方法。

mysqljs支持在query中自定义typeCast方法,可用于提取数据的步骤进行编码转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const mysql = require('mysql');
const iconv = require('iconv-lite');
const connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db',
charset : 'latin1'
});

connection.connect();

connection.query({
sql: 'SELECT * FROM tbl_user',
typeCast: (field, next) => {
// converting `tbl_user.name` to utf8 string:
if (field.name === 'username') {
return iconv.decode(field.buffer(), 'gbk');
}
return next();
}
}, (error, results, fields) => {
//
});

其中typeCast的参数field包含

  • type 字段类型,VARCHAR等(详情链接
  • name 字段名
  • length 字段长度
  • table 表名
  • db 数据库名

依此,其他更多问题都可以迎刃而解。

参考资料: