Lời hứa mysql của NodeJS
Một thẻ đã tồn tại với tên chi nhánh được cung cấp. Nhiều lệnh Git chấp nhận cả tên thẻ và tên nhánh, vì vậy việc tạo nhánh này có thể gây ra hành vi không mong muốn. Bạn có chắc chắn muốn tạo nhánh này không? Show nút-mysql-lời hứaNút. js Trình bao bọc lời hứa của thư viện MySQL Khởi tạo
Cách sử dụngconst db = require('@ikoala/node-mysql-promise') const mysqlConfig = { "host": "127.0.0.1", "user": "root", "password": "abc@123", "database": "test" } db.create('master', mysqlConfig) const query = async (val) => { const sql = 'SELECT NOW(), ?, 1' const params = [val] const rs = await db.query(sql, params) console.log(rs) // 2020-02-01 15:56:00,foo,1 } query('foo') Chức năng trợ giúpconst select = helper.createSelect('table_name', 'primary_key_field'); (async () => { await select({ all: true }) // Select all records await select(1) // Select primary key id 1 // Select field `foo` with value `bar` await select({ where: { foo: 'bar' }}) })() const insert = helper.createInsert('table_name', 'primary_key_field', { defaultFields: { ctime: () => new Date() } }); (async () => { await insert({ field1: 'foo', field2: 'bar' }) // foo,bar,[ctime date] })()thử nghiệm # Setup DB Connection and Login Credential export DB_HOST=127.0.0.1 export DB_USER=root export DB_PASSWORD=abc@123 export DB_VERBOSE=1 # Optional, enable query log phụ thuộc mysql - Nút. trình điều khiển js MySQL chức năng không đồng bộ startServer () { const client = đang chờ MongoClient. kết nối ('mongodb. //máy chủ cục bộ. 27017/quản trị viên', {useNewUrlParser. true}) ứng dụng. định nghĩa bài văn. torrentdb = máy khách. ứng dụng db('torrent'). định nghĩa bài văn. mdb = đang chờ mysql. createPool({ giới hạn kết nối. 5, máy chủ. 'máy chủ cục bộ', người dùng. 'gốc', mật khẩu. '', Hải cảng. 9306, nhiều câu lệnh. đúng }) ứng dụng. lắng nghe (quá trình. env. HẢI CẢNG. 3000, không đồng bộ () => { bảng điều khiển. log(new Date(), 'Máy chủ đang lắng nghe. ') nếu (tiến trình. gửi) { quá trình. gửi('sẵn sàng') } }) }Giống như hầu hết các hoạt động I/O trong Node. js, truy cập cơ sở dữ liệu không đồng bộ. Đó là một tính năng tuyệt vời, bởi vì các hoạt động khác có thể được thực hiện trong khi chờ đợi kết quả. Nhưng nếu bạn đến từ một ngôn ngữ lập trình khác, điều này có thể thực sự khó chịu Trong PHP, bạn chỉ cần viết $results = $connection->query( 'SELECT * FROM some_table' );// the following code is executed after the query is executed Tất nhiên, phương pháp connection.query( 'SELECT * FROM some_table', ( err, rows ) => {0 có thể mất một chút thời gian để thực thi, nhưng theo quan điểm của lập trình viên, điều đó không thực sự quan trọng. Nó hoạt động như một hoạt động nguyên tử đơn lẻ, lấy một truy vấn SQL làm đầu vào và trả về một số kết quả làm đầu ra trong nút. js, bạn phải viết một cái gì đó như thế này connection.query( 'SELECT * FROM some_table', ( err, rows ) => { Lưu ý rằng tôi đang sử dụng MySQL (dựa trên thư viện máy khách mysql) làm ví dụ, nhưng điều này cũng đúng với bất kỳ cơ sở dữ liệu nào khác, kể cả những công cụ không có SQL ưa thích đó 🙂 Được rồi, có lẽ ví dụ trên không quá tệ. Nhưng giả sử rằng bạn phải thực hiện lần lượt một số truy vấn. Và sau đó đóng kết nối, đây cũng là một hoạt động không đồng bộ connection.query( 'SELECT * FROM some_table', ( err, rows ) => { Bây giờ hãy tưởng tượng rằng có 10 truy vấn lồng nhau như thế này. Và bạn phải thêm xử lý lỗi ở cấp độ của mỗi truy vấn. Và đảm bảo rằng cơ sở dữ liệu được đóng ngay cả khi có lỗi, ở mọi cấp độ Mã như vậy sẽ rất khó viết theo cách này. Thậm chí còn khó sửa đổi hơn khi bạn phải chèn một truy vấn khác vào đâu đó ở giữa. Và chắc chắn là không thể đọc được Sử dụng lời hứaĐó là nơi những lời hứa đến để giải cứu. Nếu bạn chưa quen với khái niệm này, tôi khuyên bạn nên đọc một số phần giới thiệu trước, ví dụ tại đây hoặc tại đây. Mục đích của tôi là cho bạn thấy cách sử dụng thực tế của các lời hứa để thực hiện các truy vấn cơ sở dữ liệu tuần tự, vì vậy tôi cho rằng bạn đã biết chúng là gì Đầu tiên chúng ta phải “quảng cáo” client cơ sở dữ liệu. Bạn không cần phải làm thủ công, bạn có thể sử dụng một công cụ tự động như công cụ được mô tả ở đây, nhưng việc tạo một lớp bao bọc cho máy khách MySQL thực sự đơn giản const mysql = require( 'mysql' );class Database { Hàm tạo chỉ cần tạo một kết nối MySQL mới với cấu hình đã cho. Lưu ý rằng nó chưa mở kết nối. Kết nối được tự động mở khi truy vấn đầu tiên được thực hiện. Đó là lý do tại sao tạo kết nối không phải là hoạt động không đồng bộ Phương thức connection.query( 'SELECT * FROM some_table', ( err, rows ) => {0 lấy một chuỗi SQL và một mảng tham số tùy chọn sẽ được chuyển đến truy vấn. Nó trả về một đối tượng connection.query( 'SELECT * FROM some_table', ( err, rows ) => {2. Lời hứa sẽ được "giải quyết" khi thực hiện xong truy vấn. Các hàng được trả về sẽ là kết quả của lời hứa. Trong trường hợp có lỗi, lời hứa sẽ bị từ chối Phương pháp connection.query( 'SELECT * FROM some_table', ( err, rows ) => {3 rất giống nhau. Lời hứa được trả lại được giải quyết khi kết nối bị đóng. Nó không có bất kỳ kết quả Lưu ý rằng phương thức connection.query( 'SELECT * FROM some_table', ( err, rows ) => {0 vẫn trả về ngay lập tức, trước khi truy vấn được thực hiện. Để có được kết quả, chúng ta phải gọi phương thức connection.query( 'SELECT * FROM some_table', ( err, rows ) => {5 của lời hứa được trả về và chỉ định một chức năng sẽ được gọi khi truy vấn kết thúc thực thi Chúng ta có thể sử dụng lớp connection.query( 'SELECT * FROM some_table', ( err, rows ) => {6 mới của mình theo cách sau const select = helper.createSelect('table_name', 'primary_key_field'); (async () => { await select({ all: true }) // Select all records await select(1) // Select primary key id 1 // Select field `foo` with value `bar` await select({ where: { foo: 'bar' }}) })() const insert = helper.createInsert('table_name', 'primary_key_field', { defaultFields: { ctime: () => new Date() } }); (async () => { await insert({ field1: 'foo', field2: 'bar' }) // foo,bar,[ctime date] })()4 Lúc đầu không có ý nghĩa gì. Mã này gần giống như ví dụ đầu tiên Tuy nhiên, không giống như các cuộc gọi lại, các lời hứa có thể rất dễ dàng bị xâu chuỗi. Vì vậy, nếu chúng tôi muốn thực hiện một vài truy vấn và sau đó đóng kết nối, chúng tôi có thể làm điều gì đó như thế này const select = helper.createSelect('table_name', 'primary_key_field'); (async () => { await select({ all: true }) // Select all records await select(1) // Select primary key id 1 // Select field `foo` with value `bar` await select({ where: { foo: 'bar' }}) })() const insert = helper.createInsert('table_name', 'primary_key_field', { defaultFields: { ctime: () => new Date() } }); (async () => { await insert({ field1: 'foo', field2: 'bar' }) // foo,bar,[ctime date] })()5 Điều này dễ đọc hơn nhiều và có thể dễ dàng mở rộng nếu cần thiết. Tuy nhiên, vẫn còn hai vấn đề với giải pháp này Trích xuất kết quảVấn đề đầu tiên là trong mỗi chức năng gọi lại, chúng tôi chỉ có quyền truy cập vào kết quả của truy vấn cuối cùng. Vì vậy, nếu chúng tôi muốn làm điều gì đó với kết quả của cả hai truy vấn, chúng tôi phải lưu trữ chúng trong các biến cục bộ const select = helper.createSelect('table_name', 'primary_key_field'); (async () => { await select({ all: true }) // Select all records await select(1) // Select primary key id 1 // Select field `foo` with value `bar` await select({ where: { foo: 'bar' }}) })() const insert = helper.createInsert('table_name', 'primary_key_field', { defaultFields: { ctime: () => new Date() } }); (async () => { await insert({ field1: 'foo', field2: 'bar' }) // foo,bar,[ctime date] })()6 Lưu ý rằng để chuỗi hoạt động, các chức năng trong connection.query( 'SELECT * FROM some_table', ( err, rows ) => {5 phải trả lại lời hứa từ phương thức connection.query( 'SELECT * FROM some_table', ( err, rows ) => {0. Nếu chúng ta bỏ qua từ khóa connection.query( 'SELECT * FROM some_table', ( err, rows ) => {9, hàm connection.query( 'SELECT * FROM some_table', ( err, rows ) => {5 tiếp theo sẽ được gọi ngay với connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 1 bằng với connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 2Xử lý lỗi và đóng kết nốiNgoài ra, chúng ta không thể quên việc xử lý lỗi. Khi bất kỳ lời hứa nào trong chuỗi bị từ chối và chúng tôi không "bắt" được từ chối, chương trình của chúng tôi sẽ dừng lại với một lỗi nghiêm trọng, giống như trong trường hợp ngoại lệ chưa được xử lý Chỉ cần thêm một hàm connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 3 vào cuối toàn bộ chuỗi lời hứa là đủ. Khi xảy ra lỗi ở bất kỳ bước nào, tất cả các trình xử lý connection.query( 'SELECT * FROM some_table', ( err, rows ) => {5 tiếp theo sẽ bị bỏ qua và trình xử lý connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 3 được thực thi. Điều này khá giống với khối connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 6/connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 7Một vấn đề với giải pháp này là trong trường hợp xảy ra lỗi, kết nối sẽ không bao giờ bị đóng vì việc đóng kết nối cũng sẽ bị bỏ qua. Trong một chương trình đồng bộ, điều này có thể được thực hiện bằng cách thêm mệnh đề connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 8 vào khối connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 6/connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 7Thật không may, các lời hứa JavaScript chưa có phương thức const mysql = require( 'mysql' );class Database {1, mặc dù nó hiện đang ở giai đoạn đề xuất 2, vì vậy rất có thể nó sẽ sớm được thêm vào Để đảm bảo rằng kết nối luôn được đóng, ngay cả khi có lỗi, chúng ta có thể sử dụng đoạn mã sau $results = $connection->query( 'SELECT * FROM some_table' );// the following code is executed after the query is executed2 Hàm thứ hai được truyền cho connection.query( 'SELECT * FROM some_table', ( err, rows ) => {5, mà tôi đã đánh dấu bằng phông chữ in đậm, được gọi khi bất kỳ bước nào trước đó trong chuỗi dẫn đến lỗi. Nó đóng kết nối cơ sở dữ liệu và sau đó ném lại lỗi để nó đến trình xử lý connection.query( 'SELECT * FROM some_table', ( err, rows ) => { 3 cuối cùngNếu bạn thường sử dụng mẫu này, sẽ rất hữu ích nếu bạn tách việc tạo và đóng kết nối trong một chức năng riêng biệt như thế này $results = $connection->query( 'SELECT * FROM some_table' );// the following code is executed after the query is executed5 Ví dụ có thể được viết lại bằng chức năng này như thế này $results = $connection->query( 'SELECT * FROM some_table' );// the following code is executed after the query is executed6 Bạn có thể sử dụng một kỹ thuật tương tự để kết thúc một giao dịch. Giao dịch sẽ được tự động thực hiện khi tất cả các truy vấn được thực hiện thành công hoặc được khôi phục trong trường hợp có lỗi ghi chú cuối cùngLời hứa rất phức tạp và phải mất một thời gian để làm quen với chúng và hiểu đầy đủ về chúng. Nhưng trên thực tế, mã không đồng bộ luôn phức tạp. Các lời hứa làm cho việc viết và suy luận dễ dàng hơn một chút so với các cuộc gọi lại trần. Nếu bạn không tin tôi, hãy thử googling cho "gọi lại địa ngục" 🙂 Một điều làm cho việc viết mã không đồng bộ dễ dàng hơn so với lời hứa là các từ khóa const mysql = require( 'mysql' );class Database {4/ const mysql = require( 'mysql' );class Database {5 mới. Tôi đã sử dụng chúng trong C# một thời gian và tôi thực sự thích chúng. Chúng không được hỗ trợ bởi Node. js 6, nhưng bạn có thể sử dụng Nút. js 8 hoặc Babel Tôi đã viết phần thứ hai của bài viết này, được gọi là Nút. js, MySQL và async/await, giải thích cách sử dụng cú pháp mới này để thực hiện các thao tác cơ sở dữ liệu không đồng bộ dễ dàng hơn
|