id = 1 (integer) label = PHP (string)0 id = 1 (integer) label = PHP (string)1 id = 1 (integer) label = PHP (string)2 id = 1 (integer) label = PHP (string)3 id = 1 (integer) label = PHP (string)4 Cơ sở dữ liệu MySQL hỗ trợ các câu lệnh đã chuẩn bị. Một câu lệnh đã chuẩn bị sẵn hoặc một câu lệnh được tham số hóa được sử dụng để thực thi lặp đi lặp lại cùng một câu lệnh với hiệu quả cao và bảo vệ chống lại việc tiêm SQL quy trình làm việc cơ bản Việc thực hiện câu lệnh chuẩn bị bao gồm hai giai đoạn. chuẩn bị và thực hiện. Ở giai đoạn chuẩn bị, một mẫu câu lệnh được gửi đến máy chủ cơ sở dữ liệu. Máy chủ thực hiện kiểm tra cú pháp và khởi tạo tài nguyên nội bộ của máy chủ để sử dụng sau này Máy chủ MySQL hỗ trợ sử dụng trình giữ chỗ ẩn danh, có vị trí với id = 1 (integer) label = PHP (string)5 Chuẩn bị được theo sau bởi thực hiện. Trong quá trình thực thi, máy khách liên kết các giá trị tham số và gửi chúng đến máy chủ. Máy chủ thực thi câu lệnh với các giá trị ràng buộc bằng cách sử dụng tài nguyên nội bộ đã tạo trước đó Ví dụ #1 Tuyên bố đã chuẩn bị id = 1 (integer) label = PHP (string)6 id = 1 (integer) label = PHP (string)7 id = 1 (integer) label = PHP (string)8 id = 1 (integer) label = PHP (string)9 id = 1 (integer) label = PHP (string)0 Thực hiện lặp đi lặp lại Một câu lệnh chuẩn bị có thể được thực hiện nhiều lần. Sau mỗi lần thực hiện, giá trị hiện tại của biến bị ràng buộc được đánh giá và gửi đến máy chủ. Tuyên bố không được phân tích cú pháp một lần nữa. Mẫu sao kê không được chuyển lại máy chủ Ví dụ #2 INSERT chuẩn bị một lần, thực hiện nhiều lần id = 1 (integer) label = PHP (string)6 id = 1 (integer) label = PHP (string)7 id = 1 (integer) label = PHP (string)8 id = 1 (integer) label = PHP (string)4 id = 1 (integer) label = PHP (string)5 id = 1 (integer) label = PHP (string)6 Ví dụ trên sẽ xuất ra array(3) { [0]=> array(2) { ["id"]=> string(1) "1" ["label"]=> string(3) "PHP" } [1]=> array(2) { ["id"]=> string(1) "2" ["label"]=> string(4) "Java" } [2]=> array(2) { ["id"]=> string(1) "3" ["label"]=> string(3) "C++" } } Mọi câu lệnh đã chuẩn bị đều chiếm tài nguyên máy chủ. Các câu lệnh nên được đóng lại một cách rõ ràng ngay sau khi sử dụng. Nếu không được thực hiện một cách rõ ràng, câu lệnh sẽ bị đóng khi xử lý câu lệnh được giải phóng bởi PHP Sử dụng một câu lệnh đã chuẩn bị không phải lúc nào cũng là cách hiệu quả nhất để thực hiện một câu lệnh. Một câu lệnh đã chuẩn bị được thực hiện chỉ một lần gây ra nhiều chuyến đi khứ hồi giữa máy khách và máy chủ hơn so với câu lệnh không được chuẩn bị. Đây là lý do tại sao id = 1 (integer) label = PHP (string)7 không được chạy như một câu lệnh chuẩn bị ở trên Ngoài ra, hãy xem xét việc sử dụng cú pháp SQL multi-INSERT của MySQL cho INSERT. Ví dụ: multi-INSERT yêu cầu ít lượt đi lại giữa máy chủ và máy khách hơn so với câu lệnh đã chuẩn bị được hiển thị ở trên Ví dụ #3 Ít vòng lặp hơn bằng cách sử dụng multi-INSERT SQL id = 1 (integer) label = PHP (string)6 id = 1 (integer) label = PHP (string)9 id = 1 (integer), label = PHP (string)0 id = 1 (integer), label = PHP (string)1 Loại dữ liệu giá trị tập hợp kết quả Giao thức máy chủ máy khách MySQL xác định một giao thức truyền dữ liệu khác cho các câu lệnh đã chuẩn bị và các câu lệnh chưa chuẩn bị. Các câu lệnh đã chuẩn bị đang sử dụng cái gọi là giao thức nhị phân. Máy chủ MySQL gửi dữ liệu tập kết quả "nguyên trạng" ở định dạng nhị phân. Kết quả không được đánh số thứ tự thành chuỗi trước khi gửi. Thư viện máy khách nhận dữ liệu nhị phân và cố gắng chuyển đổi các giá trị thành các kiểu dữ liệu PHP thích hợp. Ví dụ: kết quả từ cột SQL id = 1 (integer), label = PHP (string)2 sẽ được cung cấp dưới dạng biến số nguyên PHP Ví dụ #4 Kiểu dữ liệu gốc id = 1 (integer) label = PHP (string)6 id = 1 (integer), label = PHP (string)4 id = 1 (integer), label = PHP (string)5 id = 1 (integer), label = PHP (string)6 Ví dụ trên sẽ xuất ra id = 1 (integer) label = PHP (string) Hành vi này khác với tuyên bố không chuẩn bị. Theo mặc định, các câu lệnh không chuẩn bị trả về tất cả các kết quả dưới dạng chuỗi. Mặc định này có thể được thay đổi bằng tùy chọn kết nối. Nếu tùy chọn kết nối được sử dụng, không có sự khác biệt Tìm nạp kết quả bằng các biến ràng buộc Kết quả từ các câu lệnh đã chuẩn bị có thể được truy xuất bằng cách liên kết các biến đầu ra hoặc bằng cách yêu cầu một đối tượng mysqli_result Các biến đầu ra phải được ràng buộc sau khi thực hiện câu lệnh. Một biến phải được ràng buộc cho mỗi cột của tập hợp kết quả câu lệnh Ví dụ #5 Liên kết biến đầu ra id = 1 (integer) label = PHP (string)6 id = 1 (integer), label = PHP (string)4 id = 1 (integer), label = PHP (string)9 id = 1 (integer) label = PHP (string)60 id = 1 (integer) label = PHP (string)61 Ví dụ trên sẽ xuất ra id = 1 (integer), label = PHP (string) Các câu lệnh đã chuẩn bị trả về các tập kết quả không có bộ đệm theo mặc định. Kết quả của câu lệnh không được tìm nạp và chuyển hoàn toàn từ máy chủ sang máy khách để tạo bộ đệm phía máy khách. Tập kết quả lấy tài nguyên máy chủ cho đến khi tất cả các kết quả được máy khách tìm nạp. Vì vậy nên sử dụng kết quả kịp thời. Nếu máy khách không thể tìm nạp tất cả kết quả hoặc máy khách đóng câu lệnh trước khi tìm nạp tất cả dữ liệu, thì dữ liệu phải được tìm nạp hoàn toàn trước id = 1 (integer) label = PHP (string)62 Cũng có thể đệm kết quả của câu lệnh đã chuẩn bị bằng cách sử dụng mysqli_stmt. store_result() Tìm nạp kết quả bằng giao diện mysqli_result Thay vì sử dụng kết quả bị ràng buộc, kết quả cũng có thể được truy xuất thông qua giao diện mysqli_result. mysqli_stmt. get_result() trả về tập kết quả được đệm Ví dụ #6 Sử dụng mysqli_result để lấy kết quả id = 1 (integer) label = PHP (string)6 id = 1 (integer), label = PHP (string)4 id = 1 (integer), label = PHP (string)9 id = 1 (integer) label = PHP (string)66 id = 1 (integer) label = PHP (string)67 Ví dụ trên sẽ xuất ra id = 1 (integer) label = PHP (string)6 Sử dụng giao diện mysqli_result mang lại lợi ích bổ sung cho việc điều hướng tập hợp kết quả phía máy khách linh hoạt Ví dụ #7 Bộ đệm kết quả được đặt để đọc linh hoạt id = 1 (integer) label = PHP (string)6 id = 1 (integer) label = PHP (string)69 id = 1 (integer) label = PHP (string)60 id = 1 (integer) label = PHP (string)66 id = 1 (integer) label = PHP (string)62 Ví dụ trên sẽ xuất ra id = 1 (integer) label = PHP (string)6 Thoát và tiêm SQL Các biến giới hạn được gửi đến máy chủ riêng biệt với truy vấn và do đó không thể can thiệp vào nó. Máy chủ sử dụng các giá trị này trực tiếp tại thời điểm thực thi, sau khi mẫu câu lệnh được phân tích cú pháp. Các tham số giới hạn không cần phải thoát vì chúng không bao giờ được thay thế trực tiếp vào chuỗi truy vấn. Một gợi ý phải được cung cấp cho máy chủ về loại biến bị ràng buộc, để tạo một chuyển đổi thích hợp. Xem mysqli_stmt. bind_param() để biết thêm thông tin Sự tách biệt như vậy đôi khi được coi là tính năng bảo mật duy nhất để ngăn chặn SQL injection, nhưng mức độ bảo mật tương tự có thể đạt được với các câu lệnh không chuẩn bị, nếu tất cả các giá trị được định dạng chính xác. Cần lưu ý rằng định dạng chính xác không giống như thoát và liên quan đến logic hơn so với thoát đơn giản. Do đó, các câu lệnh đã chuẩn bị chỉ đơn giản là một cách tiếp cận thuận tiện hơn và ít bị lỗi hơn đối với yếu tố bảo mật cơ sở dữ liệu này |