2017-01-31 45 views
7

Gần đây tôi đang học cách sử dụng nút và node-sqlite3 để thao tác sqlite3, đây là một mẫu.Làm thế nào để `db.serialize` hoạt động trong` node-sqlite3`

var sqlite3 = require('sqlite3'); 
var db = new sqlite3.Database(':memory:'); 
db.serialize(function() { 
    db.run("CREATE TABLE test(info TEXT)"); 
    db.run("INSERT INTO test (info) VALUES ('info1')"); 
}) 
db.close(); 

Các tài liệu nói rằng db.serialized được sử dụng để đảm bảo dòng SQL được thực hiện theo thứ tự, nhưng tôi đã nhầm lẫn, tại sao họ lại không được thực hiện theo thứ tự mà không db.serialize, sau khi tất cả họ sẽ được kéo từ hàng đợi sự kiện và thực hiện theo thứ tự? Làm thế nào nó hoạt động ở đây?

Và nếu chỉ có một sql được thực hiện, có an toàn để chạy nó mà không có db.serialize như sau không?

var sqlite3 = require('sqlite3'); 
var db = new sqlite3.Database(':memory:'); 
db.run("CREATE TABLE test(info TEXT)"); 
db.close(); 
+0

Có lẽ một trong những lý do sau: http://stackoverflow.com/a/18899872/1936319 – Sizzler

Trả lời

8

Mỗi lệnh bên trong serialize() chức năng được đảm bảo để thúc thực hiện trước khi người tiếp theo bắt đầu.

Trong ví dụ của bạn, CREATE TABLE sẽ kết thúc trước khi INSERT được chạy. Nếu bạn không sử dụng serialize() thì các tuyên bố CREATE TABLEINSERT sẽ chạy song song. Họ sẽ bắt đầu quá nhanh sau khi một khác mà INSERT thực sự có thể kết thúc trước khi bảng đã được tạo ra, cho bạn một lỗi về việc cố gắng chèn dữ liệu vào một bảng không tồn tại.

Điều này được gọi là điều kiện cuộc đua , bởi vì mỗi khi bạn chạy chương trình, bạn có thể nhận được một chiến thắng khác. Nếu CREATE TABLE thắng cuộc đua thì chương trình sẽ hoạt động tốt. Nhưng nếu INSERT thắng cuộc đua, chương trình sẽ bị lỗi. Vì bạn không thể kiểm soát ai thắng cuộc đua, serialize() sẽ dừng lại INSERT ngay cả khi bắt đầu cho đến khi CREATE TABLE đã kết thúc, đảm bảo bạn nhận được kết quả tương tự mỗi lần.

Trong ví dụ thứ hai của bạn chỉ với một tuyên bố, thì vẫn cần serialize(). Điều này là do run() bắt đầu truy vấn SQL nhưng trả về ngay, để truy vấn chạy dưới nền. Vì lệnh tiếp theo của bạn là một trong số close() cơ sở dữ liệu, bạn sẽ cắt nó trong khi truy vấn vẫn đang chạy.

serialize() không trả lại cho đến khi truy vấn nội bộ cuối cùng của nó hoàn tất, sử dụng nó sẽ giữ close() cho đến khi truy vấn hoàn tất.

Nếu bạn đang sử dụng một loại truy vấn khác (nói để phản hồi người dùng nhấp vào nút trên trang web, nơi cơ sở dữ liệu được mở giữa các cuộc gọi) thì có thể bạn sẽ không cần serialize(). Nó chỉ phụ thuộc vào việc mã sau mỗi truy vấn đòi hỏi rằng các truy vấn trước khi nó đã hoàn thành hay không.

Khi quyết định có sử dụng serialize() hay không, có thể hữu ích khi nghĩ về bất kỳ truy vấn không được tuần tự hóa nào như thể chúng được nhận xét và sau đó xem mã vẫn hoạt động. Trong ví dụ đầu tiên của bạn ở trên, việc xóa lệnh CREATE TABLE sẽ vi phạm câu lệnh INSERT sau đây (vì sau đó sẽ không có bảng để chèn vào), do đó chúng cần phải được tuần tự hóa. Nhưng nếu bạn có hai lệnh CREATE TABLE thì việc xóa một lệnh sẽ không ảnh hưởng đến lệnh kia, do đó hai lệnh này sẽ không phải được tuần tự hóa.

(Mẹo này không áp dụng cho close() tuy nhiên - những quy tắc của ngón tay cái có chỉ gọi close() khi mọi thứ đã kết thúc.)

+0

Có cách nào để đảm bảo rằng cuộc gọi run() sẽ kết thúc trước khi gọi lại được gọi? Tôi đang sử dụng serialize với một savepoint, nhưng liên tục gọi lại là trở về nhưng không có truy vấn serialized của tôi đã chạy được nêu ra và tôi thấy mã của tôi gọi gần trên cơ sở dữ liệu trước khi chúng chạy. đây là một vấn đề lớn vì tôi đang cố sử dụng dữ liệu được trả về từ các cuộc gọi này. – Michael

+0

@Michael: Không chắc chắn ý của bạn là gì bởi 'run()' có một cuộc gọi lại, nhưng có vẻ như đây là một câu hỏi mới chứ không phải là nhận xét để bạn có thể cung cấp thêm chi tiết. – Malvineous

Các vấn đề liên quan