mysql
Cài đặt
Đây là một module Node.js có sẵn thông qua npm registry.
Trước khi cài đặt, download and install Node.js. Yêu cầu Node.js phiên bản 0.6 trở lên.
Cài đặt được thực hiện bằng cách sử dụng npm install command:
$ npm install mysql
Để biết thông tin về các phiên bản 0.9.x trước đó, truy cập v0.9 branch.
Đôi khi tôi cũng có thể yêu cầu bạn cài đặt phiên bản mới nhất từ Github để kiểm tra xem việc sửa lỗi có hoạt động không. Trong trường hợp này, vui lòng thực hiện:
$ npm install mysqljs/mysql
Giới thiệu
Đây là một trình điều khiển node.js cho mysql. Nó được viết bằng JavaScript, không yêu cầu biên dịch và được cấp phép MIT 100%.
Dưới đây là một ví dụ về cách sử dụng:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.end();
Từ ví dụ này, bạn có thể tìm hiểu những điều sau:
- Mọi phương thức bạn gọi trên kết nối được đưa vào hàng đợi và thực hiện theo thứ tự.
- Đóng kết nối được thực hiện bằng cách sử dụng
end()
để đảm bảo tất cả các truy vấn còn lại được thực hiện trước khi gửi gói tin quit đến máy chủ mysql.
Người đóng góp
Cảm ơn những người đã đóng góp mã vào module này, xem GitHub Contributors page.
Bên cạnh đó, tôi muốn cảm ơn những người sau đây:
- Andrey Hristov (Oracle) – đã giúp đỡ tôi với các câu hỏi về giao thức.
- Ulf Wendel (Oracle) – đã giúp đỡ tôi với các câu hỏi về giao thức.
Nhà tài trợ
Các công ty sau đây đã hỗ trợ dự án này về mặt tài chính, cho phép tôi dành nhiều thời gian hơn cho nó (được sắp xếp theo thời gian đóng góp):
- Transloadit (công ty khởi nghiệp của tôi, chúng tôi cung cấp dịch vụ tải tệp lên & mã hóa video, hãy thử xem)
- Joyent
- pinkbike.com
- Holiday Extras (họ là hiring)
- Newscope (họ là hiring)
Cộng đồng
Nếu bạn muốn thảo luận về module này hoặc đặt câu hỏi liên quan, vui lòng sử dụng một trong những phương tiện sau:
- Danh sách thư : https://groups.google.com/forum/#!forum/node-mysql
- Kênh IRC : #node.js (trên freenode.net, tôi chú ý đến mọi tin nhắn có chứa cụm từ
mysql
)
Thiết lập kết nối
Cách được đề xuất để thiết lập một kết nối như sau:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'example.org',
user : 'bob',
password : 'secret'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
Tuy nhiên, một kết nối cũng có thể được tự động thiết lập bằng cách gọi truy vấn:
var mysql = require('mysql');
var connection = mysql.createConnection(...);
connection.query('SELECT 1', function (error, results, fields) {
if (error) throw error;
// connected!
});
Tùy theo cách bạn muốn xử lý lỗi, cả hai phương pháp đều có thể phù hợp. Bất kỳ loại lỗi kết nối nào (bắt tay hoặc mạng) đều được coi là lỗi nghiêm trọng, xem phần Error Handling để biết thêm thông tin.
Tùy chọn kết nối
Khi thiết lập kết nối, bạn có thể đặt các tùy chọn sau:
host
: Tên máy chủ của cơ sở dữ liệu mà bạn đang kết nối tới. (Mặc định:localhost
)port
: Số cổng để kết nối. (Mặc định:3306
)localAddress
: Địa chỉ IP nguồn được sử dụng cho kết nối TCP. (Tùy chọn)socketPath
: Đường dẫn đến socket miền Unix để kết nối tới. Khi sử dụng,host
vàport
sẽ bị bỏ qua.user
: Người dùng MySQL để xác thực.password
: Mật khẩu của người dùng MySQL đó.database
: Tên cơ sở dữ liệu được sử dụng cho kết nối này (Tùy chọn).charset
: Bộ mã cho kết nối. Điều này được gọi là sắp xếp trong SQL của MySQL (nhưutf8_general_ci
). Nếu chỉ định một bộ mã SQL (nhưutf8mb4
), thì sẽ sử dụng sắp xếp mặc định cho bộ mã đó. (Mặc định:'UTF8_GENERAL_CI'
)timezone
: Múi giờ được cấu hình trên máy chủ MySQL. Điều này được sử dụng để ép kiểu các giá trị ngày/giờ trên máy chủ thành đối tượngDate
của JavaScript và ngược lại. Điều này có thể là'local'
,'Z'
, hoặc một độ lệch theo định dạng+HH:MM
hoặc-HH:MM
. (Mặc định:'local'
)connectTimeout
: Số mili giây trước khi thời gian chờ kết nối tới máy chủ MySQL kết thúc. (Mặc định:10000
)stringifyObjects
: Chuyển đối tượng thành chuỗi thay vì chuyển thành giá trị. (Mặc định:false
)insecureAuth
: Cho phép kết nối tới các phiên bản MySQL yêu cầu sử dụng phương pháp xác thực cũ (không an toàn). (Mặc định:false
)typeCast
: Xác định liệu giá trị của cột có nên được chuyển đổi thành các kiểu JavaScript nguyên thủy hay không. (Mặc định:true
)queryFormat
: Một hàm định dạng truy vấn tùy chỉnh. Xem Custom format.supportBigNumbers
: Khi làm việc với các số lớn (cột BIGINT và DECIMAL) trong cơ sở dữ liệu, bạn nên bật tùy chọn này (Mặc định:false
).bigNumberStrings
: Bật cảsupportBigNumbers
vàbigNumberStrings
để luôn trả về các số lớn (cột BIGINT và DECIMAL) dưới dạng đối tượng String của JavaScript (Mặc định:false
). BậtsupportBigNumbers
nhưng đểbigNumberStrings
tắt sẽ trả về số lớn dưới dạng đối tượng String chỉ khi chúng không thể được biểu diễn chính xác bằng [đối tượng Number của JavaScript] (https://tc39.es/ecma262/#sec-ecmascript-language-types-number-type) (điều này xảy ra khi chúng vượt quá phạm vi [-2^53, +2^53]), ngược lại chúng sẽ được trả về dưới dạng đối tượng Number. Tùy chọn này sẽ bị bỏ qua nếusupportBigNumbers
bị tắt.dateStrings
: Ép kiểu các loại ngày (TIMESTAMP, DATETIME, DATE) để trả về dưới dạng chuỗi thay vì chuyển thành các đối tượng Date của JavaScript. Có thể làtrue
/false
hoặc một mảng các tên loại để giữ lại dưới dạng chuỗi. (Mặc định:false
)debug
: In chi tiết giao thức ra stdout. Có thể làtrue
/false
hoặc một mảng các tên loại gói tin cần in. (Mặc định:false
)trace
: Tạo ra các dấu vết ngăn xếp trên lỗi để bao gồm điểm gọi của thư viện (dấu vết ngăn xếp dài). Có một khoản phí hiệu suất nhỏ đối với hầu hết các cuộc gọi. (Mặc định:true
)localInfile
: Cho phépLOAD DATA INFILE
sử dụng từ khóaLOCAL
. (Mặc định:true
)multipleStatements
: Cho phép nhiều câu lệnh mysql trong mỗi truy vấn. Hãy cẩn trọng khi sử dụng, điều này có thể làm tăng khả năng tấn công SQL injection. (Mặc định:false
)flags
: Danh sách các cờ kết nối để sử dụng thay vì các cờ mặc định. Cũng có thể đưa ra danh sách các cờ mặc định bị cấm. Để biết thêm thông tin, hãy kiểm tra Connection Flags.ssl
: đối tượng với các tham số ssl hoặc một chuỗi chứa tên của hồ sơ ssl. Xem SSL options.
Ngoài việc truyền các tùy chọn này dưới dạng đối tượng, bạn cũng có thể sử dụng một chuỗi url. Ví dụ:
var connection = mysql.createConnection('mysql://user:pass@host/db?debug=true&charset=BIG5_CHINESE_CI&timezone=-0700');
Lưu ý: Các giá trị truy vấn được cố gắng phân tích dưới dạng JSON trước, và nếu thất bại thì coi chúng là chuỗi văn bản.
Tùy chọn SSL
Tùy chọn ssl
trong các tùy chọn kết nối có thể là một chuỗi hoặc một đối tượng. Khi sử dụng một chuỗi, nó sẽ sử dụng một trong các hồ sơ SSL đã được định nghĩa sẵn. Các hồ sơ SSL sau đây được bao gồm:
"Amazon RDS"
: hồ sơ này dành cho việc kết nối tới máy chủ Amazon RDS và chứa các chứng chỉ từ https://rds.amazonaws.com/doc/rds-ssl-ca-cert.pem và https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem
Khi kết nối tới các máy chủ khác, bạn sẽ cần cung cấp một đối tượng với bất kỳ tùy chọn sau đây:
ca
: Các chứng chỉ được tin tưởng thay vì các chứng chỉ mà Node.js được cấu hình để tin tưởng. Điều này liên quan đến giá trị của các chứng chỉ và không phải là tên tệp của các chứng chỉ. Điều này được truyền dưới dạng tùy chọnca
cho cuộc gọi tls.createSecureContext() dưới lớp (hoặc cuộc gọi crypto.createCredentials() nếu sử dụng Node.js dưới phiên bản 0.12).cert
: Chứng chỉ khách hàng để sử dụng trong giao tiếp SSL. Điều này được truyền dưới dạng tùy chọncert
cho cuộc gọi tls.createSecureContext() dưới lớp (hoặc cuộc gọi crypto.createCredentials() nếu sử dụng Node.js dưới phiên bản 0.12).ciphers
: Các thuật toán mã hóa sử dụng trong giao tiếp SSL thay vì các thuật toán mặc định của Node.js. Điều này được truyền dưới dạng tùy chọnciphers
cho cuộc gọi tls.createSecureContext() (hoặc cuộc gọi crypto.createCredentials() nếu sử dụng Node.js dưới phiên bản 0.12).maxVersion
: Điều này được truyền dưới dạng tùy chọnmaxVersion
cho cuộc gọi tls.createSecureContext().minVersion
: Điều này được truyền dưới dạng tùy chọnminVersion
cho cuộc gọi tls.createSecureContext().key
: Điều này được truyền dưới dạng tùy chọnkey
cho cuộc gọi tls.createSecureContext() (hoặc cuộc gọi crypto.createCredentials() nếu sử dụng Node.js dưới phiên bản 0.12).passphrase
: Điều này được truyền dưới dạng tùy chọnpassphrase
cho cuộc gọi tls.createSecureContext() (hoặc cuộc gọi crypto.createCredentials() nếu sử dụng Node.js dưới phiên bản 0.12).rejectUnauthorized
: Chứng chỉ máy chủ được xác minh so với danh sách các CAs được cung cấp và tên máy chủ, và nếu không tìm thấy sự khớp, kết nối SSL sẽ thất bại. (Mặc định:true
)
Dưới đây là một ví dụ đơn giản:
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
ca : fs.readFileSync(__dirname + '/mysql-ca.crt')
}
});
Bạn cũng có thể kết nối tới máy chủ MySQL mà không cung cấp chính xác CA thích hợp để tin tưởng. Bạn không nên làm điều này.
var connection = mysql.createConnection({
host : 'localhost',
ssl : {
// DO NOT DO THIS
// set up your ca correctly to trust the connection
rejectUnauthorized: false
}
});
Cờ kết nối
Nếu, vì bất kỳ lý do nào, bạn muốn thay đổi các cờ kết nối mặc định, bạn có thể sử dụng tùy chọn kết nối flags
. Truyền một chuỗi chứa danh sách các mục được phân cách bằng dấu phẩy để thêm vào các cờ mặc định. Nếu bạn không muốn sử dụng một cờ mặc định, hãy thêm dấu trừ vào trước cờ đó. Để thêm một cờ không có trong danh sách mặc định, chỉ cần viết tên cờ, hoặc thêm tiền tố bằng dấu cộng (không phân biệt hoa thường).
var connection = mysql.createConnection({
// disable FOUND_ROWS flag, enable IGNORE_SPACE flag
flags: '-FOUND_ROWS,IGNORE_SPACE'
});
Các cờ sau đây có sẵn:
COMPRESS
– Bật nén giao thức. Tính năng này hiện không được hỗ trợ bởi triển khai Node.js nên không thể bật. (Mặc định tắt)CONNECT_WITH_DB
– Khả năng chỉ định cơ sở dữ liệu khi kết nối. (Mặc định bật)FOUND_ROWS
– Gửi số hàng tìm thấy thay vì số hàng ảnh hưởng dưới dạngaffectedRows
. (Mặc định bật)IGNORE_SIGPIPE
– Không phát ra SIGPIPE khi xảy ra lỗi mạng. Cờ này không ảnh hưởng đến triển khai Node.js này. (Mặc định bật)IGNORE_SPACE
– Cho phép trình phân tích bỏ qua các khoảng trống trước ký tự(
trong các truy vấn. (Mặc định bật)INTERACTIVE
– Báo cho máy chủ MySQL rằng đây là một máy khách “tương tác”. Điều này sẽ sử dụng các thời gian chờ tương tác trên máy chủ MySQL và thông báo là tương tác trong danh sách quy trình. (Mặc định tắt)LOCAL_FILES
– Có thể sử dụngLOAD DATA LOCAL
. Cờ này được điều khiển bởi tùy chọn kết nốilocalInfile
. (Mặc định bật)LONG_FLAG
– Cờ dài hơn trong Protocol::ColumnDefinition320. (Mặc định bật)LONG_PASSWORD
– Sử dụng phiên bản cải tiến của Xác thực Mật khẩu Cũ. (Mặc định bật)MULTI_RESULTS
– Có thể xử lý nhiều kết quả cho các truy vấn. (Mặc định bật)MULTI_STATEMENTS
– Máy khách có thể gửi nhiều câu lệnh cho mỗi truy vấn hoặc câu lệnh chuẩn bị (phân tách bởi;
). Cờ này được điều khiển bởi tùy chọn kết nốimultipleStatements
. (Mặc định tắt)NO_SCHEMA
ODBC
Xử lý đặc biệt của hành vi ODBC. Cờ này không ảnh hưởng đến triển khai Node.js này. (Mặc định bật)PLUGIN_AUTH
– Sử dụng cơ chế xác thực plugin khi kết nối tới máy chủ MySQL. Tính năng này hiện không được hỗ trợ bởi triển khai Node.js nên không thể bật. (Mặc định tắt)PROTOCOL_41
– Sử dụng giao thức 4.1. (Mặc định bật)PS_MULTI_RESULTS
– Có thể xử lý nhiều kết quả cho câu lệnh thực thi. (Mặc định bật)REMEMBER_OPTIONS
– Điều này chỉ đối với máy khách C, và không ảnh hưởng đến triển khai Node.js này. (Mặc định tắt)RESERVED
– Cờ cũ cho giao thức 4.1. (Mặc định bật)SECURE_CONNECTION
– Hỗ trợ xác thực 4.1 native. (Mặc định bật)SSL
– Sử dụng SSL sau bước bắt tay để mã hóa dữ liệu trong quá trình truyền. Tính năng này được điều khiển thông qua tùy chọn kết nốissl
, vì vậy cờ này không có tác dụng. (Mặc định tắt)SSL_VERIFY_SERVER_CERT
– Xác minh chứng chỉ của máy chủ trong quá trình thiết lập SSL. Tính năng này được điều khiển thông qua tùy chọn kết nốissl.rejectUnauthorized
, vì vậy cờ này không có tác dụng. (Mặc định tắt)TRANSACTIONS
– Yêu cầu cờ trạng thái giao dịch. (Mặc định bật)
Chấm dứt kết nối
Có hai cách để chấm dứt kết nối. Chấm dứt kết nối một cách êm thấm là thông qua việc gọi phương thức end()
:
connection.end(function(err) {
// The connection is terminated now
});
Điều này sẽ đảm bảo tất cả các truy vấn đã được đưa vào hàng đợi trước đó vẫn được thực thi trước khi gửi một gói tin COM_QUIT
tới máy chủ MySQL. Nếu có lỗi nghiêm trọng xảy ra trước khi gói tin COM_QUIT
được gửi đi, một đối số err
sẽ được cung cấp cho hàm gọi lại, nhưng kết nối sẽ được chấm dứt bất kể điều đó.
Một cách thay thế khác để kết thúc kết nối là gọi phương thức destroy()
. Điều này sẽ dẫn đến việc chấm dứt ngay lập tức của ổ cắm cơ bản. Ngoài ra, destroy()
đảm bảo không có sự kiện hoặc gọi lại nào khác sẽ được kích hoạt cho kết nối.
connection.destroy();
Không giống như end()
, phương thức destroy()
không nhận đối số gọi lại.
Gom nhóm kết nối
Thay vì tạo và quản lý kết nối một cách riêng lẻ, module này cũng cung cấp tích hợp sẵn việc gom nhóm kết nối bằng cách sử dụng mysql.createPool(config)
. Read more about connection pooling.
Tạo một bể gom nhóm và sử dụng nó trực tiếp:
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
});
pool.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
Đây là một phím tắt cho quá trình mã pool.getConnection()
-> connection.query()
-> connection.release()
. Sử dụng pool.getConnection()
hữu ích để chia sẻ trạng thái kết nối cho các truy vấn tiếp theo. Điều này bởi vì hai cuộc gọi đến pool.query()
có thể sử dụng hai kết nối khác nhau và chạy song song. Đây là cấu trúc cơ bản:
var mysql = require('mysql');
var pool = mysql.createPool(...);
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
Nếu bạn muốn đóng kết nối và loại bỏ nó khỏi bể, hãy sử dụng connection.destroy()
thay vào đó. Bể sẽ tạo một kết nối mới lần tới khi cần.
Các kết nối được tạo ra một cách lười biếng bởi bể. Nếu bạn cấu hình bể cho phép tối đa 100 kết nối, nhưng chỉ sử dụng đồng thời 5 kết nối, thì chỉ có 5 kết nối được tạo. Các kết nối cũng được tuần hoàn theo kiểu round-robin, với các kết nối được lấy từ đầu bể và trả lại đáy bể.
Khi một kết nối trước đó được lấy từ bể, một gói tin ping được gửi đến máy chủ để kiểm tra xem kết nối có còn tốt hay không.
Tùy chọn bể
Bể chấp nhận tất cả các options as a connection. Khi tạo một kết nối mới, các tùy chọn được truyền đơn giản cho constructor kết nối. Ngoài các tùy chọn đó, bể còn chấp nhận một số tùy chọn khác:
acquireTimeout
: Số mili giây trước khi quá thời gian chờ trong quá trình thu thập kết nối. Điều này hơi khác biệt so vớiconnectTimeout
, vì việc thu thập một kết nối trong bể không luôn luôn bao gồm việc tạo một kết nối. Nếu một yêu cầu kết nối được đưa vào hàng đợi, thời gian yêu cầu ở trong hàng đợi không tính trong thời gian chờ này. (Mặc định:10000
)waitForConnections
: Xác định hành động của bể khi không có kết nối nào khả dụng và đã đạt đến giới hạn. Nếutrue
, bể sẽ đưa yêu cầu kết nối vào hàng đợi và gọi nó khi có sẵn. Nếufalse
, bể sẽ ngay lập tức gọi lại với lỗi. (Mặc định:true
)connectionLimit
: Số lượng tối đa kết nối được tạo cùng một lúc. (Mặc định:10
)queueLimit
: Số lượng yêu cầu kết nối tối đa mà bể sẽ đưa vào hàng đợi trước khi trả về một lỗi từgetConnection
. Nếu thiết lập thành0
, không có giới hạn cho số yêu cầu kết nối đang chờ trong hàng đợi. (Mặc định:0
)
Sự kiện bể
acquire
Bể sẽ phát ra sự kiện acquire
khi một kết nối được thu thập từ bể. Điều này được gọi sau khi tất cả hoạt động thu thập đã được thực hiện trên kết nối, ngay trước khi kết nối được gửi đến hàm gọi lại của mã thu thập.
pool.on('acquire', function (connection) {
console.log('Connection %d acquired', connection.threadId);
});
connection
Bể sẽ phát ra sự kiện connection
khi một kết nối mới được tạo trong bể. Nếu bạn cần thiết lập biến phiên trên kết nối trước khi sử dụng nó, bạn có thể lắng nghe sự kiện connection
.
pool.on('connection', function (connection) {
connection.query('SET SESSION auto_increment_increment=1')
});
enqueue
Bể sẽ phát ra sự kiện enqueue
khi một hàm gọi lại đã được đưa vào hàng đợi để chờ kết nối khả dụng.
pool.on('enqueue', function () {
console.log('Waiting for available connection slot');
});
release
Bể sẽ phát ra sự kiện release
khi một kết nối được trả lại vào bể. Điều này được gọi sau khi tất cả hoạt động trả lại đã được thực hiện trên kết nối, vì vậy kết nối sẽ được liệt kê là miễn phí tại thời điểm sự kiện.
pool.on('release', function (connection) {
console.log('Connection %d released', connection.threadId);
});
Đóng tất cả các kết nối trong bể
Khi bạn đã sử dụng xong bể, bạn phải kết thúc tất cả các kết nối hoặc vòng lặp sự kiện Node.js sẽ vẫn hoạt động cho đến khi các kết nối được đóng bởi máy chủ MySQL. Điều này thường được thực hiện nếu bể được sử dụng trong một kịch bản hoặc khi cố gắng tắt máy chủ một cách êm thấm. Để kết thúc tất cả các kết nối trong bể, sử dụng phương thức end
trên bể:
pool.end(function (err) {
// all connections in the pool have ended
});
Phương thức end
có thể nhận một tùy chọn callback mà bạn có thể sử dụng để biết khi tất cả các kết nối đã kết thúc.
Một khi**pool.end**
được gọi,**pool.getConnection**
và các hoạt động khác không thể được thực hiện nữa. Đợi cho đến khi tất cả các kết nối trong bể được giải phóng trước khi gọi pool.end
. Nếu bạn sử dụng phương thức phím tắt pool.query
, thay vì pool.getConnection
→ connection.query
→ connection.release
, hãy đợi cho đến khi nó hoàn thành.
pool.end
gọi connection.end
trên mỗi kết nối hoạt động trong bể. Điều này đặt một gói tin QUIT
vào kết nối và đặt một cờ để ngăn pool.getConnection
tạo ra các kết nối mới. Tất cả các lệnh / truy vấn đang tiến hành sẽ hoàn thành, nhưng các lệnh mới sẽ không thực thi.
PoolCluster
PoolCluster cung cấp kết nối nhiều máy chủ. (nhóm & thử lại & bộ chọn)
// create
var poolCluster = mysql.createPoolCluster();
// add configurations (the config is a pool config object)
poolCluster.add(config); // add configuration with automatic name
poolCluster.add('MASTER', masterConfig); // add a named configuration
poolCluster.add('SLAVE1', slave1Config);
poolCluster.add('SLAVE2', slave2Config);
// remove configurations
poolCluster.remove('SLAVE2'); // By nodeId
poolCluster.remove('SLAVE*'); // By target group : SLAVE1-2
// Target Group : ALL(anonymous, MASTER, SLAVE1-2), Selector : round-robin(default)
poolCluster.getConnection(function (err, connection) {});
// Target Group : MASTER, Selector : round-robin
poolCluster.getConnection('MASTER', function (err, connection) {});
// Target Group : SLAVE1-2, Selector : order
// If can't connect to SLAVE1, return SLAVE2. (remove SLAVE1 in the cluster)
poolCluster.on('remove', function (nodeId) {
console.log('REMOVED NODE : ' + nodeId); // nodeId = SLAVE1
});
// A pattern can be passed with * as wildcard
poolCluster.getConnection('SLAVE*', 'ORDER', function (err, connection) {});
// The pattern can also be a regular expression
poolCluster.getConnection(/^SLAVE[12]$/, function (err, connection) {});
// of namespace : of(pattern, selector)
poolCluster.of('*').getConnection(function (err, connection) {});
var pool = poolCluster.of('SLAVE*', 'RANDOM');
pool.getConnection(function (err, connection) {});
pool.getConnection(function (err, connection) {});
pool.query(function (error, results, fields) {});
// close all connections
poolCluster.end(function (err) {
// all connections in the pool cluster have ended
});
Tùy chọn PoolCluster
canRetry
: Nếutrue
,PoolCluster
sẽ cố gắng kết nối lại khi kết nối thất bại. (Mặc định:true
)removeNodeErrorCount
: Nếu kết nối thất bại,errorCount
của nút tăng lên. KhierrorCount
lớn hơnremoveNodeErrorCount
, loại bỏ một nút trongPoolCluster
. (Mặc định:5
)restoreNodeTimeout
: Nếu kết nối thất bại, xác định số mili giây trước khi một lần thử kết nối khác sẽ được thực hiện. Nếu thiết lập thành0
, thì nút sẽ bị loại bỏ thay vì không bao giờ được sử dụng lại. (Mặc định:0
)defaultSelector
: Bộ chọn mặc định. (Mặc định:RR
)RR
: Lựa chọn lần lượt. (Round-Robin)RANDOM
: Chọn nút bằng chức năng ngẫu nhiên.-
ORDER
: Chọn nút đầu tiên khả dụng mà không điều kiện.var clusterConfig = {
removeNodeErrorCount: 1, // Remove the node immediately when connection fails.
defaultSelector: ‘ORDER’
};var poolCluster = mysql.createPoolCluster(clusterConfig);
Chuyển đổi người dùng và thay đổi trạng thái kết nối
MySQL cung cấp một lệnh changeUser
cho phép bạn thay đổi người dùng hiện tại và các khía cạnh khác của kết nối mà không cần tắt ngắt socket cơ bản:
connection.changeUser({user : 'john'}, function(err) {
if (err) throw err;
});
Các tùy chọn có sẵn cho tính năng này là:
user
: Tên người dùng mới (mặc định là người trước đó).password
: Mật khẩu của người dùng mới (mặc định là mật khẩu trước đó).charset
: Bảng mã mới (mặc định là bảng mã trước đó).database
: Cơ sở dữ liệu mới (mặc định là cơ sở dữ liệu trước đó).
Một hiệu ứng phụ có ích đôi khi của chức năng này là chức năng này cũng đặt lại bất kỳ trạng thái kết nối nào (biến, giao dịch, vv.).
Lỗi gặp phải trong quá trình này được xem xét là lỗi kết nối chết ngay lập tức bởi mô-đun này.
Ngắt kết nối của máy chủ
Bạn có thể mất kết nối đến máy chủ MySQL do vấn đề mạng, máy chủ hết thời gian chờ, máy chủ được khởi động lại hoặc bị sập. Tất cả các sự kiện này được coi là lỗi chết ngay lập tức, và sẽ có err.code = 'PROTOCOL_CONNECTION_LOST'
. Xem phần Error Handling để biết thêm thông tin.
Kết nối lại một kết nối được thực hiện bằng cách thiết lập một kết nối mới. Một khi bị chấm dứt, một đối tượng kết nối hiện có không thể được kết nối lại theo thiết kế.
Với Bể, các kết nối bị ngắt sẽ được loại bỏ khỏi bể, giải phóng không gian để tạo ra kết nối mới trong cuộc gọi getConnection
tiếp theo.
Với PoolCluster
, các kết nối bị ngắt sẽ được tính là lỗi đối với nút liên quan, tăng mã lỗi cho nút đó. Một khi có nhiều hơn removeNodeErrorCount
lỗi trên một nút cụ thể, nó sẽ bị loại bỏ khỏi cụm. Khi điều này xảy ra, PoolCluster
có thể phát ra một lỗi POOL_NONEONLINE
nếu không còn các nút phù hợp cho mẫu nữa. Cấu hình restoreNodeTimeout
có thể được đặt để phục hồi các nút ngoại tuyến sau một khoảng thời gian nhất định.
Thực hiện các truy vấn
Cách đơn giản nhất để thực hiện một truy vấn là gọi phương thức .query()
trên một đối tượng (như một thể hiện Connection
, Pool
, hoặc PoolNamespace
).
Biểu thức đơn giản nhất của .query()
là .query(sqlString, callback)
, trong đó chuỗi SQL là đối số đầu tiên và thứ hai là một hàm callback:
connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
Biểu thức thứ hai .query(sqlString, values, callback)
được sử dụng khi sử dụng giá trị giữ chỗ (xem escaping query values):
connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
Biểu thức thứ ba .query(options, callback)
xuất hiện khi sử dụng các tùy chọn nâng cao khác trên truy vấn, như escaping query values, joins with overlapping column names, timeouts, và type casting.
connection.query({
sql: 'SELECT * FROM `books` WHERE `author` = ?',
timeout: 40000, // 40s
values: ['David']
}, function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
Lưu ý rằng có thể sử dụng sự kết hợp giữa biểu thức thứ hai và thứ ba trong trường hợp các giá trị giữ chỗ được truyền dưới dạng đối số và không nằm trong đối tượng tùy chọn. Đối số values
sẽ ghi đè lên values
trong đối tượng tùy chọn.
connection.query({
sql: 'SELECT * FROM `books` WHERE `author` = ?',
timeout: 40000, // 40s
},
['David'],
function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
}
);
Nếu truy vấn chỉ có một ký tự thay thế (?
) và giá trị không phải là null
, undefined
, hoặc một mảng, nó có thể được truyền trực tiếp làm đối số thứ hai cho .query
:
connection.query(
'SELECT * FROM `books` WHERE `author` = ?',
'David',
function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
}
);
Điều chỉnh giá trị truy vấn
Cảnh báo Những phương pháp thoát khỏi giá trị chỉ hoạt động khi chế độ SQL NO_BACKSLASH_ESCAPES bị tắt (đây là trạng thái mặc định cho máy chủ MySQL).
Cảnh báo Thư viện này thực hiện việc thoát khỏi phía máy khách, vì đây là một thư viện để tạo ra chuỗi SQL trên phía máy khách. Cú pháp cho các hàm như mysql.format
có thể trông giống như một câu lệnh được chuẩn bị trước, nhưng thực chất không phải vậy, và các quy tắc thoát khỏi từ mô-đun này được sử dụng để tạo ra chuỗi SQL kết quả. Mục đích của việc thoát khỏi đầu vào là để tránh các cuộc tấn công SQL Injection. Để hỗ trợ việc định dạng tùy chỉnh như SET
và IN
, mô-đun này sẽ thoát khỏi dựa trên hình dạng của giá trị JavaScript được truyền vào, và chuỗi đã thoát khỏi kết quả có thể lớn hơn một giá trị đơn. Khi đầu vào cấu trúc của người dùng được cung cấp làm giá trị để thoát khỏi, cần phải kiểm tra kỹ hơn để xác minh rằng hình dạng của đầu ra sẽ như mong đợi.
Để tránh các cuộc tấn công SQL Injection, bạn nên luôn thoát khỏi bất kỳ dữ liệu được cung cấp bởi người dùng trước khi sử dụng chúng trong một truy vấn SQL. Bạn có thể làm điều này bằng cách sử dụng các phương thức mysql.escape()
, connection.escape()
hoặc pool.escape()
:
var userId = 'some user provided value';
var sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId);
connection.query(sql, function (error, results, fields) {
if (error) throw error;
// ...
});
Hoặc, bạn có thể sử dụng ký tự ?
như các giữ chỗ cho các giá trị mà bạn muốn thoát khỏi như sau:
connection.query('SELECT * FROM users WHERE id = ?', [userId], function (error, results, fields) {
if (error) throw error;
// ...
});
Nhiều giữ chỗ được ánh xạ thành các giá trị theo cùng thứ tự như được truyền. Ví dụ, trong truy vấn sau, foo
tương đương với a
, bar
tương đương với b
, baz
tương đương với c
, và id
sẽ là userId
:
connection.query('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', ['a', 'b', 'c', userId], function (error, results, fields) {
if (error) throw error;
// ...
});
Điều này trông giống như các câu lệnh được chuẩn bị trước trong MySQL, tuy nhiên thực sự chỉ sử dụng cùng một phương thức connection.escape()
bên trong.
Cảnh báo Điều này cũng khác biệt so với câu lệnh được chuẩn bị trước trong việc thay thế tất cả các ?
, kể cả những ?
được chứa trong các comment và chuỗi.
Các loại giá trị khác nhau được thoát khỏi một cách khác nhau, dưới đây là cách:
- Số không bị thay đổi
- Giá trị Boolean được chuyển đổi thành
true
/false
- Đối tượng Date được chuyển đổi thành chuỗi
'YYYY-mm-dd HH:ii:ss'
- Buffers được chuyển đổi thành chuỗi hex, ví dụ:
X'0fa5'
- Chuỗi được thoát an toàn
- Mảng được chuyển thành danh sách, ví dụ:
['a', 'b']
trở thành'a', 'b'
- Mảng lồng nhau được chuyển thành danh sách nhóm (cho việc chèn hàng loạt), ví dụ:
[['a', 'b'], ['c', 'd']]
trở thành('a', 'b'), ('c', 'd')
- Đối tượng có phương thức
toSqlString
sẽ được gọi.toSqlString()
và giá trị trả về được sử dụng làm SQL raw. - Đối tượng được chuyển thành các cặp
key = 'val'
cho mỗi thuộc tính đếm được trên đối tượng. Nếu giá trị của thuộc tính là một hàm, nó sẽ được bỏ qua; nếu giá trị của thuộc tính là một đối tượng, hàm toString() được gọi và giá trị trả về được sử dụng. undefined
/null
được chuyển thànhNULL
NaN
/Infinity
được giữ nguyên. MySQL không hỗ trợ chúng và cố gắng chèn chúng như các giá trị sẽ gây ra lỗi MySQL cho đến khi họ thực hiện hỗ trợ.
Cách thoát này cho phép bạn thực hiện những điều thú vị như sau:
var post = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function (error, results, fields) {
if (error) throw error;
// Neat!
});
console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
Và phương thức toSqlString
cho phép bạn tạo ra các truy vấn phức tạp với các hàm:
var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } };
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
Để tạo ra các đối tượng có phương thức toSqlString
, bạn có thể sử dụng phương thức mysql.raw()
. Điều này tạo ra một đối tượng sẽ được giữ nguyên khi sử dụng trong một ?
placeholder, hữu ích để sử dụng các hàm như các giá trị động:
Cẩn trọng Chuỗi được cung cấp cho mysql.raw()
sẽ bỏ qua tất cả các hàm thoát khi sử dụng, vì vậy hãy cẩn thận khi truyền vào đầu vào chưa được xác thực.
var CURRENT_TIMESTAMP = mysql.raw('CURRENT_TIMESTAMP()');
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
Nếu bạn cảm thấy cần phải tự mình thoát truy vấn, bạn cũng có thể sử dụng hàm thoát trực tiếp:
var query = "SELECT * FROM posts WHERE title=" + mysql.escape("Hello MySQL");
console.log(query); // SELECT * FROM posts WHERE title='Hello MySQL'
Thoát các định danh truy vấn
Nếu bạn không thể tin tưởng một định danh SQL (tên cơ sở dữ liệu / bảng / cột) vì nó được cung cấp bởi người dùng, bạn nên thoát nó bằng mysql.escapeId(identifier)
, connection.escapeId(identifier)
hoặc pool.escapeId(identifier)
như sau:
var sorter = 'date';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter);
connection.query(sql, function (error, results, fields) {
if (error) throw error;
// ...
});
Nó cũng hỗ trợ thêm định danh có chứng chỉ. Nó sẽ thoát cả hai phần.
var sorter = 'date';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter);
// -> SELECT * FROM posts ORDER BY `posts`.`date`
Nếu bạn không muốn coi .
như là định danh có chứng chỉ, bạn có thể đặt đối số thứ hai thành true
để giữ chuỗi như một định danh văn bản:
var sorter = 'date.2';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter, true);
// -> SELECT * FROM posts ORDER BY `date.2`
Hoặc bạn có thể sử dụng ký tự ??
như là chỗ giữ chỗ cho các định danh bạn muốn thoát như sau:
var userId = 1;
var columns = ['username', 'email'];
var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function (error, results, fields) {
if (error) throw error;
// ...
});
console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
Vui lòng lưu ý rằng chuỗi ký tự cuối cùng này là thử nghiệm và cú pháp có thể thay đổi
Khi bạn truyền một Đối tượng vào .escape()
hoặc .query()
, .escapeId()
được sử dụng để tránh tấn công SQL injection trong các khóa đối tượng.
Chuẩn bị Truy vấn
Bạn có thể sử dụng mysql.format
để chuẩn bị một truy vấn với nhiều điểm chèn, sử dụng cách thoát đúng cho các id và giá trị. Một ví dụ đơn giản như sau:
var sql = "SELECT * FROM ?? WHERE ?? = ?";
var inserts = ['users', 'id', userId];
sql = mysql.format(sql, inserts);
Sau đó, bạn có một truy vấn hợp lệ và đã được thoát, bạn có thể gửi an toàn đến cơ sở dữ liệu. Điều này hữu ích nếu bạn muốn chuẩn bị truy vấn trước khi thực sự gửi nó đến cơ sở dữ liệu. Vì mysql.format
được tiết lộ từ SqlString.format
, bạn cũng có tùy chọn (nhưng không bắt buộc) để truyền vào stringifyObject
và timezone
, cho phép bạn cung cấp một phương pháp tùy chỉnh để chuyển các đối tượng thành chuỗi, cũng như một Ngày cụ thể về vị trí / múi giờ.
Định dạng tùy chỉnh
Nếu bạn muốn có một loại định dạng thoát truy vấn khác, có một tùy chọn cấu hình kết nối bạn có thể sử dụng để xác định một hàm định dạng tùy chỉnh. Bạn có thể truy cập đối tượng kết nối nếu bạn muốn sử dụng .escape()
tích hợp sẵn hoặc bất kỳ chức năng kết nối nào khác.
Dưới đây là một ví dụ về cách triển khai một định dạng khác:
connection.config.queryFormat = function (query, values) {
if (!values) return query;
return query.replace(/\:(\w+)/g, function (txt, key) {
if (values.hasOwnProperty(key)) {
return this.escape(values[key]);
}
return txt;
}.bind(this));
};
connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
Lấy id của hàng đã chèn
Nếu bạn đang chèn một hàng vào một bảng với khóa chính tự tăng, bạn có thể lấy id chèn như sau:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
Khi làm việc với các số lớn (vượt quá giới hạn độ chính xác của Số JavaScript), bạn nên xem xét bật tùy chọn supportBigNumbers
để có thể đọc id chèn dưới dạng chuỗi, nếu không sẽ gây ra lỗi.
Tùy chọn này cũng cần thiết khi lấy các số lớn từ cơ sở dữ liệu, nếu không bạn sẽ nhận được các giá trị làm tròn đến hàng trăm hoặc hàng nghìn do giới hạn độ chính xác.
Lấy số hàng bị ảnh hưởng
Bạn có thể lấy số hàng bị ảnh hưởng từ câu lệnh chèn, cập nhật hoặc xóa.
connection.query('DELETE FROM posts WHERE title = "wrong"', function (error, results, fields) {
if (error) throw error;
console.log('deleted ' + results.affectedRows + ' rows');
})
Lấy số hàng thay đổi
Bạn có thể lấy số hàng thay đổi từ câu lệnh cập nhật.
“changedRows” khác với “affectedRows” ở chỗ nó không tính các hàng được cập nhật mà giá trị của chúng không thay đổi.
connection.query('UPDATE posts SET ...', function (error, results, fields) {
if (error) throw error;
console.log('changed ' + results.changedRows + ' rows');
})
Lấy ID kết nối
Bạn có thể lấy ID kết nối MySQL (“ID luồng”) của một kết nối cụ thể bằng cách sử dụng thuộc tính threadId
.
connection.connect(function(err) {
if (err) throw err;
console.log('connected as id ' + connection.threadId);
});
Thực hiện truy vấn song song
Giao thức MySQL là tuần tự, điều này có nghĩa bạn cần nhiều kết nối để thực hiện các truy vấn song song. Bạn có thể sử dụng một Pool để quản lý các kết nối, một cách tiếp cận đơn giản là tạo một kết nối cho mỗi yêu cầu http đến.
Truy vấn dòng dữ liệu dạng luồng
Đôi khi bạn có thể muốn chọn một lượng lớn dòng và xử lý từng dòng khi chúng được nhận. Điều này có thể được thực hiện như sau:
var query = connection.query('SELECT * FROM posts');
query
.on('error', function(err) {
// Handle error, an 'end' event will be emitted after this as well
})
.on('fields', function(fields) {
// the field packets for the rows to follow
})
.on('result', function(row) {
// Pausing the connnection is useful if your processing involves I/O
connection.pause();
processRow(row, function() {
connection.resume();
});
})
.on('end', function() {
// all rows have been received
});
Lưu ý một số điều về ví dụ ở trên:
- Thông thường, bạn sẽ muốn nhận một số lượng dòng cụ thể trước khi bắt đầu kiểm soát kết nối bằng cách sử dụng
pause()
. Số lượng này sẽ phụ thuộc vào số lượng và kích thước của các dòng của bạn. pause()
/resume()
hoạt động trên socket và bộ phân tích cơ bản. Bạn được đảm bảo rằng không có sự kiện nào về'result'
sẽ xảy ra sau khi gọipause()
.- BẠN KHÔNG ĐƯỢC cung cấp một callback cho phương thức
query()
khi dòng dữ liệu được truyền dạng luồng. - Sự kiện
'result'
sẽ xảy ra cho cả dòng lẫn gói tin OK xác nhận thành công của truy vấn INSERT/UPDATE. - Rất quan trọng không để kết quả bị tạm dừng quá lâu, hoặc bạn có thể gặp phải lỗi
Error: Connection lost: Máy chủ đã đóng kết nối.
Thời gian giới hạn cho điều này được xác định bởi net_write_timeout setting trên máy chủ MySQL của bạn.
Ngoài ra, bạn có thể quan tâm biết hiện tại không thể truyền luồng từng cột của dòng một cách riêng lẻ, chúng luôn được đệm hoàn toàn. Nếu bạn có một trường hợp sử dụng tốt cho việc truyền luồng các trường lớn đến và từ MySQL, tôi rất mong nhận được ý kiến và đóng góp của bạn về vấn đề này.
Đưa kết quả vào luồng với Streams
Đối tượng truy vấn cung cấp một phương thức tiện ích .stream([options])
giúp bọc các sự kiện truy vấn vào một đối tượng Readable Stream. Dòng dữ liệu này có thể dễ dàng được đưa vào luồng dưới và cung cấp tính năng tạm dừng/tiếp tục tự động, dựa trên tắc nghẽn dưới luồng và highWaterMark
tùy chọn. Tham số objectMode
của luồng được đặt thành true
và không thể thay đổi (nếu bạn cần một luồng byte, bạn sẽ cần sử dụng một luồng biến đổi, như objstream ví dụ).
Ví dụ, đưa kết quả truy vấn vào một luồng khác (với bộ đệm tối đa 5 đối tượng) đơn giản như sau:
connection.query('SELECT * FROM posts')
.stream({highWaterMark: 5})
.pipe(...);
Truy vấn chứa nhiều câu lệnh
Hỗ trợ cho nhiều câu lệnh bị vô hiệu hóa vì lý do bảo mật (nó cho phép tấn công SQL injection nếu các giá trị không được thoát đúng cách). Để sử dụng tính năng này, bạn phải bật nó cho kết nối của bạn:
var connection = mysql.createConnection({multipleStatements: true});
Sau khi bật, bạn có thể thực thi truy vấn chứa nhiều câu lệnh giống như bất kỳ truy vấn nào khác:
connection.query('SELECT 1; SELECT 2', function (error, results, fields) {
if (error) throw error;
// `results` is an array with one element for every statement in the query:
console.log(results[0]); // [{1: 1}]
console.log(results[1]); // [{2: 2}]
});
Ngoài ra, bạn cũng có thể đưa dữ liệu kết quả của truy vấn chứa nhiều câu lệnh vào một luồng:
var query = connection.query('SELECT 1; SELECT 2');
query
.on('fields', function(fields, index) {
// the fields for the result rows that follow
})
.on('result', function(row, index) {
// index refers to the statement this result belongs to (starts at 0)
});
Nếu một trong các câu lệnh trong truy vấn gây ra lỗi, đối tượng Lỗi kết quả chứa một thuộc tính err.index
cho biết câu lệnh nào gây ra lỗi. MySQL cũng sẽ ngừng thực thi bất kỳ câu lệnh còn lại khi xảy ra lỗi.
Lưu ý rằng giao diện cho việc đưa dữ liệu kết quả của truy vấn chứa nhiều câu lệnh vào luồng là thử nghiệm và tôi rất mong nhận phản hồi về nó.
Thủ tục lưu trữ
Bạn có thể gọi các thủ tục lưu trữ từ các truy vấn của bạn giống như bất kỳ trình điều khiển mysql nào khác. Nếu thủ tục lưu trữ tạo ra một loạt kết quả, chúng được hiển thị cho bạn cách tương tự như kết quả cho các truy vấn chứa nhiều câu lệnh.
Ghép bảng với tên cột chồng chéo
Khi thực thi các phép ghép bảng, bạn có khả năng nhận được các kết quả với tên cột chồng chéo.
Mặc định, node-mysql sẽ ghi đè lên các tên cột trùng nhau theo thứ tự các cột được nhận từ MySQL, dẫn đến việc một số giá trị nhận được không khả dụng.
Tuy nhiên, bạn cũng có thể chỉ định rằng bạn muốn các cột của mình được lồng vào dưới tên bảng như sau:
var options = {sql: '...', nestTables: true};
connection.query(options, function (error, results, fields) {
if (error) throw error;
/* results will be an array like this now:
[{
table1: {
fieldA: '...',
fieldB: '...',
},
table2: {
fieldA: '...',
fieldB: '...',
},
}, ...]
*/
});
Hoặc sử dụng một ký tự phân tách chuỗi để kết quả được gộp lại.
var options = {sql: '...', nestTables: '_'};
connection.query(options, function (error, results, fields) {
if (error) throw error;
/* results will be an array like this now:
[{
table1_fieldA: '...',
table1_fieldB: '...',
table2_fieldA: '...',
table2_fieldB: '...',
}, ...]
*/
});
Giao dịch
Hỗ trợ giao dịch đơn giản có sẵn ở cấp độ kết nối:
connection.beginTransaction(function(err) {
if (err) { throw err; }
connection.query('INSERT INTO posts SET title=?', title, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
var log = 'Post ' + results.insertId + ' added';
connection.query('INSERT INTO log SET data=?', log, function (error, results, fields) {
if (error) {
return connection.rollback(function() {
throw error;
});
}
connection.commit(function(err) {
if (err) {
return connection.rollback(function() {
throw err;
});
}
console.log('success!');
});
});
});
});
Vui lòng lưu ý rằng beginTransaction(), commit() và rollback() chỉ đơn giản là các chức năng tiện ích thực thi các lệnh START TRANSACTION, COMMIT và ROLLBACK tương ứng. Quan trọng là hiểu rằng nhiều lệnh trong MySQL có thể gây ra một giao dịch tự động, như được mô tả in the MySQL documentation.
Ping
Một gói tin ping có thể được gửi qua một kết nối bằng cách sử dụng phương thức connection.ping
. Phương thức này sẽ gửi một gói tin ping đến máy chủ và khi máy chủ phản hồi, lời gọi lại sẽ được kích hoạt. Nếu xảy ra lỗi, lời gọi lại sẽ được kích hoạt với đối số lỗi.
connection.ping(function (err) {
if (err) throw err;
console.log('Server responded to ping');
})
Thời gian chờ
Mọi thao tác đều có tùy chọn thời gian chờ không hoạt động tùy chọn. Điều này cho phép bạn chỉ định thời gian chờ phù hợp cho các thao tác. Quan trọng là lưu ý rằng các thời gian chờ này không phải là một phần của giao thức MySQL, mà thay vào đó là thời gian chờ thao tác thông qua máy khách. Điều này có nghĩa là khi đạt đến thời gian chờ, kết nối mà nó xảy ra sẽ bị hủy và không thể thực hiện thêm thao tác nào khác.
// Kill query after 60s
connection.query({sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000}, function (error, results, fields) {
if (error && error.code === 'PROTOCOL_SEQUENCE_TIMEOUT') {
throw new Error('too long to count table rows!');
}
if (error) {
throw error;
}
console.log(results[0].count + ' rows');
});
Xử lý lỗi
Module này đi kèm với một phương pháp xử lý lỗi nhất quán mà bạn nên xem xét cẩn thận để viết các ứng dụng đáng tin cậy.
Hầu hết các lỗi được tạo ra bởi module này là các trường hợp của đối tượng Error JavaScript. Ngoài ra, chúng thường đi kèm với hai thuộc tính bổ sung:
err.code
: Chuỗi, chứa ký hiệu lỗi máy chủ MySQL nếu lỗi là một MySQL server error (ví dụ như'ER_ACCESS_DENIED_ERROR'
), một mã lỗi Node.js nếu đó là lỗi Node.js (ví dụ như'ECONNREFUSED'
), hoặc một mã lỗi nội bộ (ví dụ như'PROTOCOL_CONNECTION_LOST'
).err.errno
: Số, chứa số lỗi máy chủ MySQL. Chỉ được điền từ MySQL server error.err.fatal
: Boolean, cho biết nếu lỗi này là lỗi chấm dứt cho đối tượng kết nối. Nếu lỗi không phải từ một hoạt động giao thức MySQL, thuộc tính này sẽ không được định nghĩa.err.sql
: Chuỗi, chứa câu SQL đầy đủ của truy vấn thất bại. Điều này có thể hữu ích khi sử dụng giao diện cấp cao hơn như ORM đang tạo các truy vấn.err.sqlState
: Chuỗi, chứa giá trị SQLSTATE gồm năm ký tự. Chỉ được điền từ MySQL server error.err.sqlMessage
: Chuỗi, chứa chuỗi thông báo cung cấp mô tả văn bản về lỗi. Chỉ được điền từ MySQL server error.
Các lỗi chấm dứt được lan truyền đến tất cả các lời gọi lại đang chờ. Trong ví dụ dưới đây, một lỗi chấm dứt được kích hoạt bằng cách cố gắng kết nối đến cổng bị chặn. Do đó, đối tượng lỗi được truyền đến cả hai lời gọi lại đang chờ:
var connection = require('mysql').createConnection({
port: 1 // example blocked port
});
connection.connect(function(err) {
console.log(err.code); // 'ECONNREFUSED'
console.log(err.fatal); // true
});
connection.query('SELECT 1', function (error, results, fields) {
console.log(error.code); // 'ECONNREFUSED'
console.log(error.fatal); // true
});
Tuy nhiên, các lỗi bình thường chỉ được gửi đến lời gọi lại mà chúng thuộc về. Vì vậy, trong ví dụ dưới đây, chỉ lời gọi lại đầu tiên nhận được lỗi, truy vấn thứ hai hoạt động như mong đợi:
connection.query('USE name_of_db_that_does_not_exist', function (error, results, fields) {
console.log(error.code); // 'ER_BAD_DB_ERROR'
});
connection.query('SELECT 1', function (error, results, fields) {
console.log(error); // null
console.log(results.length); // 1
});
Cuối cùng nhưng không kém: Nếu xảy ra lỗi chấm dứt và không có lời gọi lại đang chờ, hoặc xảy ra lỗi bình thường mà không có lời gọi lại thuộc về nó, lỗi được phát ra như một sự kiện 'error'
trên đối tượng kết nối. Điều này được minh họa trong ví dụ dưới đây:
connection.on('error', function(err) {
console.log(err.code); // 'ER_BAD_DB_ERROR'
});
connection.query('USE name_of_db_that_does_not_exist');
Lưu ý: Sự kiện 'error'
là đặc biệt trong node. Nếu chúng xảy ra mà không có trình nghe được gắn kèm, một dấu vết ngăn xếp được in và quá trình của bạn bị kết thúc.
tl;dr: Mô-đun này không muốn bạn đối mặt với những lỗi im lặng. Bạn nên luôn cung cấp các callback cho các cuộc gọi phương thức của bạn. Nếu bạn muốn bỏ qua lời khuyên này và làm tắt các lỗi chưa được xử lý, bạn có thể làm như sau:
// I am Chuck Norris:
connection.on('error', function() {});
An Toàn Khi Xảy Ra Ngoại Lệ
Mô-đun này đảm bảo an toàn khi xảy ra ngoại lệ. Điều này có nghĩa là bạn có thể tiếp tục sử dụng nó, ngay cả khi một trong các hàm callback của bạn gây ra lỗi mà bạn đang bắt bằng cách sử dụng ‘uncaughtException’ hoặc một miền.
Ép kiểu
Để tiện lợi cho bạn, trình điều khiển này sẽ tự động ép kiểu các loại mysql thành các loại JavaScript nguyên bản theo mặc định. Hành vi mặc định có thể được thay đổi thông qua các Connection options. Các ánh xạ sau đây tồn tại:
Số
- TINYINT
- SMALLINT
- INT
- MEDIUMINT
- YEAR
- FLOAT
- DOUBLE
- BIGINT
Ngày
- TIMESTAMP
- DATE
- DATETIME
Bộ đệm
- TINYBLOB
- MEDIUMBLOB
- LONGBLOB
- BLOB
- BINARY
- VARBINARY
- BIT (byte cuối cùng sẽ được điền đầy đủ với các bit 0 cần thiết)
Chuỗi
Lưu ý văn bản trong bộ ký tự nhị phân được trả về dưới dạng Buffer
, thay vì là một chuỗi.
- CHAR
- VARCHAR
- TINYTEXT
- MEDIUMTEXT
- LONGTEXT
- TEXT
- ENUM
- SET
- DECIMAL (có thể vượt quá độ chính xác của số float)
- TIME (có thể được ánh xạ thành Ngày, nhưng ngày nào sẽ được đặt?)
- GEOMETRY (không bao giờ sử dụng những cái đó, liên hệ nếu bạn sử dụng)
Không được khuyến nghị (và có thể sẽ bị loại bỏ / thay đổi trong tương lai) để vô hiệu hóa việc ép kiểu, nhưng bạn hiện tại có thể làm như vậy trên kết nối:
var connection = require('mysql').createConnection({typeCast: false});
Hoặc trên cấp độ truy vấn:
var options = {sql: '...', typeCast: false};
var query = connection.query(options, function (error, results, fields) {
if (error) throw error;
// ...
});
Ép kiểu tùy chỉnh
Bạn cũng có thể truyền một hàm và tự quản lý việc ép kiểu. Bạn sẽ được cung cấp một số thông tin cột như cơ sở dữ liệu, bảng và tên, cũng như loại và độ dài. Nếu bạn chỉ muốn áp dụng ép kiểu tùy chỉnh cho một loại cụ thể, bạn có thể làm như vậy và sau đó quay trở lại kiểu mặc định.
Hàm được cung cấp hai đối số field
và next
và cần trả về giá trị cho trường cụ thể bằng cách gọi các hàm phân tích thông qua đối tượng field
.
Đối số field
là một đối tượng Field
và chứa dữ liệu về trường cần phân tích. Dưới đây là một số thuộc tính trên đối tượng Field
:
db
– một chuỗi cho biết cơ sở dữ liệu mà trường đến từ.table
– một chuỗi cho biết bảng mà trường đến từ.name
– một chuỗi cho biết tên trường.type
– một chuỗi cho biết loại trường viết hoa.length
– một số cho biết độ dài của trường, như được cung cấp bởi cơ sở dữ liệu.
Đối số next
là một function
mà khi gọi, sẽ trả về việc chuyển đổi kiểu mặc định cho trường cụ thể.
Khi lấy dữ liệu trường, các phương thức trợ giúp sau được cung cấp trên đối tượng field
:
.string()
– phân tích trường thành một chuỗi..buffer()
– phân tích trường thành mộtBuffer
..geometry()
– phân tích trường như một giá trị hình học.
Giao thức MySQL là một giao thức dựa trên văn bản. Điều này có nghĩa là qua dây truyền, tất cả các loại trường đều được biểu diễn dưới dạng một chuỗi, đó là lý do tại sao chỉ các chức năng tương tự chuỗi có sẵn trên đối tượng field
. Dựa vào thông tin loại (như INT
), việc ép kiểu nên chuyển đổi trường chuỗi thành một loại JavaScript khác (như một number
).
Dưới đây là một ví dụ về việc chuyển đổi TINYINT(1)
thành boolean:
connection = mysql.createConnection({
typeCast: function (field, next) {
if (field.type === 'TINY' && field.length === 1) {
return (field.string() === '1'); // 1 = true, 0 = false
} else {
return next();
}
}
});
CẢNH BÁO: BẠN PHẢI GỌI trình phân tích bằng cách sử dụng một trong ba chức năng trường này trong cuộc gọi callback typeCast tùy chỉnh của bạn. Chúng chỉ có thể được gọi một lần.
Gỡ lỗi và báo cáo vấn đề
Nếu bạn gặp vấn đề, một điều có thể giúp là bật chế độ debug
cho kết nối:
var connection = mysql.createConnection({debug: true});
Điều này sẽ in tất cả các gói tin gửi và nhận trên stdout. Bạn cũng có thể hạn chế gỡ lỗi cho các loại gói tin bằng cách truyền một mảng các loại vào debug:
var connection = mysql.createConnection({debug: ['ComQueryPacket', 'RowDataPacket']});
để hạn chế gỡ lỗi cho các gói truy vấn và dữ liệu.
Nếu điều đó không giúp, hãy mở một vấn đề trên GitHub. Một vấn đề tốt trên GitHub sẽ bao gồm:
- Số lượng mã tối thiểu cần thiết để tái hiện vấn đề (nếu có thể)
- Càng nhiều đầu ra gỡ lỗi và thông tin về môi trường của bạn (phiên bản mysql, phiên bản node, hệ điều hành, v.v.) càng tốt.
Vấn đề bảo mật
Vấn đề bảo mật không nên được báo cáo lần đầu thông qua GitHub hoặc một diễn đàn công khai khác, mà nên được giữ bí mật để các cộng tác viên đánh giá báo cáo và sau đó (a) lập kế hoạch vá và lên lịch phát hành hoặc (b) xác nhận rằng đó không phải là một vấn đề bảo mật (trong trường hợp đó nó có thể được đăng trên diễn đàn công khai, như một vấn đề trên GitHub).
Diễn đàn riêng chính là email, thông qua việc gửi email cho tác giả của mô-đun hoặc mở một vấn đề trên GitHub chỉ đơn giản là hỏi vấn đề bảo mật nên được gửi đến ai mà không tiết lộ vấn đề hoặc loại vấn đề.
Một báo cáo lý tưởng sẽ bao gồm một chỉ dẫn rõ ràng về vấn đề bảo mật là gì và cách nó sẽ được khai thác, lý tưởng kèm theo một bằng chứng thực hiện (“PoC”) để các cộng tác viên làm việc và xác minh sửa chữa tiềm năng.
Đóng góp
Dự án này hoan nghênh sự đóng góp từ cộng đồng. Đóng góp được chấp nhận bằng cách gửi yêu cầu kéo (pull requests) trên GitHub. Nếu bạn không quen thuộc với việc tạo pull request trên GitHub, vui lòng tham khảo GitHub documentation “Creating a pull request”.
Đối với một pull request tốt, chúng tôi yêu cầu bạn cung cấp các thông tin sau:
. Cố gắng bao gồm một mô tả rõ ràng về pull request của bạn trong phần mô tả. Nó nên bao gồm các “what” và “why” cơ bản cho yêu cầu.
. Các kiểm tra nên được hoàn thành tốt nhất có thể. Xem phần Running tests về cách chạy các kiểm tra khác nhau. GitHub sẽ tự động chạy các kiểm tra này, như một lưới an toàn.
. Pull request nên bao gồm các kiểm tra cho sự thay đổi. Một tính năng mới nên có các kiểm tra cho tính năng mới và sửa lỗi nên bao gồm một kiểm tra thất bại nếu không có sự thay đổi mã tương ứng và sau khi áp dụng chúng. Lệnh npm run test-cov
sẽ tạo ra một thư mục coverage/
chứa các trang HTML về phủ sóng mã, để hiểu rõ hơn xem tất cả những gì bạn đang thêm đã được kiểm tra.
. Nếu pull request là một tính năng mới, hãy chắc chắn bao gồm tất cả các bổ sung tài liệu thích hợp trong tệp Readme.md
nữa.
. Để đảm bảo rằng mã của bạn có cùng phong cách với mã hiện có, chạy lệnh npm run lint
và sửa các vấn đề hiển thị.
Chạy kiểm tra
Bộ kiểm tra được chia thành hai phần: kiểm tra đơn vị và kiểm tra tích hợp. Kiểm tra đơn vị chạy trên bất kỳ máy tính nào trong khi kiểm tra tích hợp đòi hỏi phải thiết lập một phiên bản máy chủ MySQL.
Chạy kiểm tra đơn vị
$ FILTER=unit npm test
Chạy kiểm tra tích hợp
Đặt các biến môi trường MYSQL_DATABASE
, MYSQL_HOST
, MYSQL_PORT
, MYSQL_USER
và MYSQL_PASSWORD
. MYSQL_SOCKET
cũng có thể được sử dụng thay thế cho MYSQL_HOST
và MYSQL_PORT
để kết nối qua ổ cắm UNIX. Sau đó chạy lệnh npm test
.
Ví dụ, nếu bạn có cài đặt mysql chạy trên localhost:3306 và không có mật khẩu cho người dùng root
, chạy:
$ mysql -u root -e "CREATE DATABASE IF NOT EXISTS node_mysql_test"
$ MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_DATABASE=node_mysql_test MYSQL_USER=root MYSQL_PASSWORD= FILTER=integration npm test
Công việc cần làm
- Các câu lệnh chuẩn bị
- Hỗ trợ các mã hóa khác ngoài UTF-8 / ASCII
Chi tiết tải về:
Tác giả: mysqljs
Nguồn: https://github.com/mysqljs/mysql
Giấy phép: MIT license