我知道使用PreparedStatement
的优点,
但我想知道何时使用它代替Statement
?
答案 0 :(得分:26)
查询由数据库服务器重写和编译
如果你不使用准备好的 声明,数据库服务器将 必须解析,并计算一个 声明的执行计划 每次运行它。如果你找到了 你将运行相同的声明 多次(有不同的 参数)然后它值得准备 声明一次并重复使用 准备好的声明如果你是 然后查询数据库adhoc 可能没什么好处 此
防止SQL注入
这几乎是你的优势
总是希望有一个很好的理由
每次都使用PreparedStatement
。
这是必须的结果
参数化查询,但确实如此
使运行更安全。该
只有我能想到这一点
如果你是的话会没用
允许adhoc数据库查询;您
可能只是使用Statement
对象如果你是原型的话
应用程序及其更快,
或者如果查询包含否
参数。
答案 1 :(得分:17)
问汤姆的opinion:
在JDBC中使用Statement应该100%本地化以用于DDL(ALTER, CREATE,GRANT等)因为这些是唯一不能接受BIND的语句类型 变量。
PreparedStatements或CallableStatements应该用于其他类型的语句 (DML,查询)。因为这些是接受绑定变量的语句类型。
这是一个事实,一个规则,一个法律 - 使用准备好的声明无处不在。使用STATEMENTS 几乎没有。
他特别谈论Oracle,但同样的原则适用于任何缓存执行计划的数据库。
同时扩展和防止SQL注入攻击的数据库应用程序?有什么缺点?
答案 2 :(得分:9)
我会转向这一轮:在公开发布的应用中,你应该总是使用准备好的陈述,除非你有一个非常令人信服的理由不,你应该总是为准备好的语句“正确”提供参数,而不是将它们拼接到查询字符串中。
为什么呢?好吧,基本上是因为你给出的原因(或者至少是第二个)......
答案 3 :(得分:5)
在WHERE子句中应该非常小心地使用PreparedStatements。
假设一个表定义为:
create table t (int o, k varchar(100), v varchar(100))
(例如“o:object-ID(外键),k:attribute-key,v:attribute-value”)。
此外,v。
上有一个(非唯一的)索引create index ixt on t ( v )
假设此表包含2亿行插入,如:
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));
}
(“因此,每个对象o都有属性k1 = v1和k2 = o”)
然后你不应该构建如下的查询:
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=?
(“查找具有两个给定属性的对象”)
我对ORACLE和MSSQL的经验是,这些查询可能需要很多分钟才能返回。即使没有行匹配where子句也是如此。这取决于SQL-Server决定首先查找tx.v或ty.v。
一个人将列k和v的值直接放入语句中。我认为这是因为SQL Server在计算执行计划时会考虑这些值。
查询看起来总是在毫秒之后返回:
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将始终首先搜索v ='1234',然后搜索v ='v1'”)
问候
沃尔夫冈
答案 4 :(得分:1)
语句:每次运行sql查询时,都会将此sql语句发送到编译它的DBMS。因此,它会增加服务器负载并降低性能。
connection con=null;
String sql="select * from employee where id=5";
Statement st=conn.createStatement();
PreparedStatement :与Statement PreparedStatement不同,在创建时将sql查询作为参数提供。
connection con=null;
String sql="select * from employee where id=?";
PreparedStatement ps=conn.prepareStatement(sql);
此sql语句将发送到数据库,并在其中进行编译。 因此,在preparedStatement中,编译只发生一次,但在每次调用Statement时都会发生语句编译。
答案 5 :(得分:1)
您始终可以使用PreparedStatement而不是Statment(选择,插入,更新,删除)。更好的性能并防止SQL注入。
但是,请不要将其与动态请求一起使用,例如WHERE variable IN [ hundreds possibilities ]
的请求:
它适得其反,你失去了性能和内存,因为每次新请求都会缓存,而PreparedStatement不只是用于SQL注入,而是关于性能。在这种情况下,Statement不会慢。
您的游泳池有一个PreparedStatment限制(-1 defaut但你必须限制它),你将达到这个限制!如果你没有限制或非常大的限制你有一些内存泄漏的风险,并在极端情况下OutofMemory错误。因此,如果它适用于3个用户使用的小型个人项目,那么它并不具有戏剧性,但如果您是一家大公司并且您不想要这样做,那么您就不会想要这样做了。应用程序被千人和百万请求使用。
一些阅读。 IBM : Periodical OutOfMemory errors with prepared statement caching
答案 6 :(得分:1)
这只是Java DESIGN MISTAKE将“ prepared statement”与“ parameterized query / bind variables”联系在一起。
数据库确实具有API来接受仅运行一次的SQL代码中的“绑定变量”。
这是一个巨大的资源浪费,在每个地方都使用“ prepared statement”来保护SQL注入。为什么Java不让开发人员以正确的方式使用数据库?
可能如下:
Statement Interface
-可以运行多个命令。不接受绑定变量。 SQL命令的一次执行。没有SQL注入保护。
PreparedStatement Interface
-可以运行一个命令。接受绑定变量。
SQL命令的多次执行。 SQL注入保护。
(在JAVA中丢失!)RunOnceStatement
-可以运行一个命令。接受绑定变量。 SQL命令的一次执行。 SQL注入保护。
例如,通过将驱动程序映射到:
,在Postgres中的性能可能会更好。
Statement Interface
-PQExec()
PreparedStatement Interface
-PQPrepare() / PQExecPrepare() / ...
(JAVA中缺少!)RunOnceStatement
-PQExecParams()
在SQL代码中使用仅运行一次的预备语句是一个很大的性能问题:通过维护计划(稍后将不再调用),数据库中的更多处理将浪费数据库内存。缓存计划太过拥挤,以至于可以从缓存中删除多次执行的实际SQL命令。
答案 7 :(得分:0)
除了防止SQL注入,格式化可移植性(你无法从Statement
获得),性能是显而易见的原因。但是,PreparedStatement
并非没有任何惩罚。例如,如果只运行一次,它通常比Statement
慢,因为有一些开销。因此,当您多次执行相同的查询时,应该使用PreparedStatement
。但是,特定于数据库服务器实现的开销是多少,因此从性能考虑中确切地选择PreparedStatement
而不是Statement
时,应该基于您对特定数据库服务器的实际经验/实验。