Câu hỏi Khi nào chúng ta nên sử dụng một PreparedStatement thay vì một tuyên bố?


Tôi biết những lợi thế của việc sử dụng PreparedStatement, là

  • truy vấn được viết lại và biên dịch bởi máy chủ cơ sở dữ liệu
  • bảo vệ chống lại SQL injection

Nhưng tôi muốn biết khi nào chúng ta sử dụng nó thay vì Statement?


24
2018-01-20 06:23


gốc


có thể trùng lặp Báo cáo chuẩn bị và hiệu suất - sarnold


Các câu trả lời:


  1. Truy vấn được viết lại và biên dịch bởi máy chủ cơ sở dữ liệu

    Nếu bạn không sử dụng một chuẩn bị tuyên bố, máy chủ cơ sở dữ liệu sẽ phải phân tích cú pháp và tính toán kế hoạch thực hiện cho tuyên bố mỗi khi bạn chạy nó. Nếu bạn tìm thấy bạn sẽ chạy cùng một câu lệnh nhiều lần (với khác nhau các thông số) sau đó chuẩn bị giá trị của nó tuyên bố một lần và tái sử dụng tuyên bố chuẩn bị. Nếu bạn là truy vấn adhoc cơ sở dữ liệu sau đó có lẽ ít lợi ích cho điều này.

  2. Được bảo vệ chống lại SQL injection

    Đây là một lợi thế bạn gần như luôn luôn muốn như vậy một lý do chính đáng để sử dụng một PreparedStatement mỗi lần. Một hệ quả của việc phải tham số hóa truy vấn nhưng nó làm cho nó chạy an toàn hơn rất nhiều. Các chỉ có thời gian tôi mới có thể nghĩ rằng điều này sẽ không hữu ích nếu bạn là cho phép truy vấn cơ sở dữ liệu adhoc; Bạn có thể chỉ cần sử dụng Tuyên bố đối tượng nếu bạn đang tạo mẫu ứng dụng và nhanh hơn cho bạn, hoặc nếu truy vấn không chứa thông số.


25
2018-01-20 06:34





Hỏi Tom's ý kiến:

Việc sử dụng Tuyên bố trong JDBC phải được bản địa hoá 100% để được sử dụng cho DDL (ALTER, TẠO, GRANT, v.v ... vì đây là các loại câu lệnh duy nhất không thể chấp nhận BIND BIẾN.

Các câu lệnh được lập sẵn hoặc các lệnh có thể gọi được sử dụng cho MỌI loại câu lệnh khác (DML, Truy vấn). Vì đây là các loại câu lệnh chấp nhận các biến liên kết.

Đây là một thực tế, một quy tắc, một luật - sử dụng báo cáo chuẩn bị MỌI NGƯỜI. Sử dụng STATEMENTS hầu như không có ở đâu.


16
2018-01-20 07:03





Tôi sẽ quay vòng này: trong một ứng dụng được phân phối công khai, bạn nên nói chung luôn luôn sử dụng báo cáo đã chuẩn bị trừ khi bạn có một lý do thực sự thuyết phục khôngvà bạn nên luôn cung cấp các tham số "đúng" cho câu lệnh đã chuẩn bị, chứ không phải bằng cách nối chúng vào chuỗi truy vấn.

Tại sao? Vâng, về cơ bản vì những lý do bạn đưa ra (hoặc ít nhất, lý do thứ hai) ...


9
2018-01-20 06:40



Lưu ý: Hiệu suất của một PreparedStatement có thể là abysmal trừ khi bạn làm rất nhiều hoạt động với nó. Đây là tùy thuộc vào trình điều khiển cơ sở dữ liệu. - Thorbjørn Ravn Andersen
Cảm ơn, đó là một điểm thú vị. Không quan tâm, bạn có ví dụ về một trình điều khiển / DB cụ thể trong trường hợp này không? Từ các bài kiểm tra tôi đã thực hiện với MySQL, có vẻ như không có bất cứ điều gì trong nó hiệu suất khôn ngoan. Đừng chỉ nhớ với SQL Server, mặc dù không nhớ các câu lệnh chuẩn bị đặc biệt xấu. - Neil Coffey


PreparedStatements nên được sử dụng rất cẩn thận trong mệnh đề WHERE.

Giả sử rằng một bảng được định nghĩa là:

create table t (int o, k varchar(100), v varchar(100))

(ví dụ: "o: ID đối tượng (khóa ngoại), k: thuộc tính-khóa, v: thuộc tính-giá trị").

Hơn nữa có một chỉ số (không duy nhất) trên v.

create index ixt on t ( v )

Giả sử rằng bảng này chứa 200 triệu hàng được chèn vào như:

for (i = 0; i < 100*1000*1000; i++) {
  insert into t (o,k,v) values (i,'k1','v1');
  insert into t (o,k,v) values (i,'k2', Convert(i, varchar));
}

("Như vậy, mọi đối tượng o có các thuộc tính k1 = v1 và k2 = o")

Sau đó, bạn không nên tạo các truy vấn như:

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k=? and tx.v=? and ty.k=? and ty.v=?

("tìm đối tượng có hai thuộc tính nhất định")

Kinh nghiệm của tôi với ORACLE và MSSQL là, những truy vấn đó có thể cần nhiều phút trở về. Điều này đúng ngay cả khi không có hàng khớp với mệnh đề where. Nó phụ thuộc vào thời điểm SQL Server quyết định tra cứu tx.v hoặc ty.v trước.

Một shoud đặt các giá trị cho các cột k và v directy vào báo cáo. Tôi nghĩ rằng điều này là do các máy chủ SQL đưa các giá trị vào tài khoản khi tính toán kế hoạch thực hiện.

Một truy vấn trông như thế này trả về luôn sau mili giây:

select o,p,v from t as tx, t as ty where tx.o=ty.o and tx.k='k1' and tx.v='v1' and ty.k='k2' and ty.v='1234'

("SQL-Server sẽ luôn luôn tìm kiếm đầu tiên cho v = '1234' và sau đó cho v = 'v1'")

Trân trọng
Wolfgang


5
2017-11-22 19:08





Tôi thích sử dụng PreparedStatement  nếu tôi muốn thực hiện một truy vấn. (Chèn, Chọn, ... vv). Cùng rasoson mà những người khác viết ở trên.

Nhưng nếu tôi cần sử dụng tham số động Tôi chỉ đơn giản là Tuyên bố bởi vì tôi có thể dễ dàng xây dựng chuỗi SQL của tôi thhan chỉ đơn giản là thực thi. (theo ý kiến ​​của tôi) Nếu bạn muốn xây dựng truy vấn động với preparStatment, bạn sẽ có một mã spaghetti lớn mà không ai hiểu được.


1
2017-11-19 08:06



Bạn thích nhưng đó là cách tồi tệ nhất để làm. Ưu điểm của PreparedStatement nằm trong các tham số động. - amdev
Tôi có nghĩa là năng động trong số lượng paramters. Không phải giá trị tham số là động ... - Farkas Csanád
Tôi hiểu, tôi nghĩ bạn nên lưu trữ thông số động của mình trong bản đồ <order, param> khi bạn tạo truy vấn động của mình. Nhưng nó tẻ nhạt. - amdev


Bên cạnh việc ngăn chặn SQL injection, định dạng tính di động (mà bạn không thể nhận được từ Statement), hiệu suất là lý do rõ ràng. Tuy nhiên, PreparedStatement không đến mà không bị phạt. Ví dụ, nó thường chậm hơn Statement nếu chỉ chạy một lần, vì có một số chi phí. Ý tưởng chung là PreparedStatement nên được sử dụng khi bạn thực hiện cùng một truy vấn nhiều lần. Tuy nhiên, bao nhiêu chi phí là rất cơ sở dữ liệu máy chủ thực hiện cụ thể, do đó, chính xác khi nào nên chọn PreparedStatement kết thúc Statement, từ việc xem xét hiệu suất, nên thực sự dựa trên trải nghiệm thực tế / thử nghiệm của một máy chủ cơ sở dữ liệu cụ thể.


0
2018-01-20 06:42





Tuyên bố: Mỗi lần truy vấn sql đang chạy, câu lệnh sql này được gửi đến DBMS nơi nó được biên dịch. Vì vậy, nó làm tăng tải máy chủ và giảm hiệu suất.

connection con=null; 
  String sql="select * from employee where id=5";
Statement st=conn.createStatement();

PreparedStatement: Không giống như Statement PreparedStatement được đưa ra một truy vấn sql như một tham số khi nó được tạo ra.

connection con=null; 
String sql="select * from employee where id=?";
PreparedStatement ps=conn.prepareStatement(sql);

Câu lệnh sql này được gửi đến Database nơi nó được biên dịch. Vì vậy, trong PrepareStatement được biên dịch xảy ra chỉ một lần nhưng trong câu lệnh được biên dịch xảy ra mỗi khi câu lệnh được gọi.


0
2017-11-28 06:32