什么时候应该使用PreparedStatement而不是Statement?
我知道使用PreparedStatement
的好处,
- 查询由数据库服务器重写和编译
- 防止SQL注入
但是我想知道什么时候用它来代替Statement
?
-
查询由数据库服务器重写和编译
如果您不使用准备好的语句,数据库服务器将不得不分析,并且每次运行时都要为语句计算执行计划。 如果你发现你会多次运行相同的语句(使用不同的参数),那么它的价值就是一次准备语句,并重用这个准备好的语句。 如果您正在查询数据库adhoc,那么可能没有什么好处。
-
防止SQL注入
这是您几乎总是需要的优势,因此每次使用
PreparedStatement
都是一个很好的理由。 它的参数化查询的后果,但它确实使运行更安全。 我唯一能想到的是,如果你允许adhoc数据库查询的话,这是没有用的。 如果您原型化了应用程序,并且其速度更快,或者查询中不包含任何参数,则可以简单地使用Statement对象。
问汤姆的意见 :
在JDBC中使用Statement应该被100%本地化以用于DDL(ALTER,CREATE,GRANT等),因为这些是唯一不能接受BIND VARIABLES的语句types。
PreparedStatements或CallableStatements应该用于每个其他types的语句(DML,查询)。 因为这些是接受绑定variables的语句types。
这是一个事实,一个规则,一个法律使用准备无处不在的声明。 使用STATEMENTS几乎没有地方。
他正在专门讨论Oracle,但同样的原则适用于caching执行计划的任何数据库。
数据库应用程序同时扩展和防止SQL注入攻击? 有什么缺点?
我将转向这一轮:在一个公开分发的应用程序中,通常应该使用准备好的语句, 除非你有一个非常有说服力的理由不要 ,而且你应该总是向准备好的语句“正确地”提供参数,而不是把它们拼接成查询string。
为什么? 那么,主要是因为你给的原因(或者至less是第二个)…
PreparedStatements应该在WHERE子句中使用得非常仔细。
假设一个表被定义为:
create table t (int o, k varchar(100), v varchar(100))
(例如“o:object-ID(外键),k:属性键,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)); }
(“因此,每个对象都有属性k1 = v1和k2 = o”)
那么你不应该build立像这样的查询:
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总是先searchv ='1234',然后searchv ='v1'”)
问候
沃尔夫冈
如果我想执行一个查询,我更喜欢使用PreparedStatement 。 (插入,select…等)。 与上面写的其他人相同的是rasoson。
但是,如果我需要使用dynamic参数,我使用简单的语句,因为我可以轻松地build立我的stringSQL,只是执行。 (inmyopinion)如果你想用prepareStatment构builddynamic查询,你将会有一个没有人理解的庞大的意大利面代码。
除了防止SQL注入,格式化可移植性(你不能从Statement
获得),性能是明显的原因。 但是, PreparedStatement
并不是没有任何惩罚。 例如,如果只运行一次,它通常比Statement
慢,因为有一些开销。 所以一般的想法是PreparedStatement
应该用在多次执行相同查询的时候。 但是,数据库服务器特定于实现的开销多less,因此,从性能angular度考虑,确切何时从Statement
selectPreparedStatement
,应该基于您对特定数据库服务器的实际体验/实验。
声明 :每次sql查询运行时,这个sql语句都被发送到编译它的DBMS。 所以,它增加了服务器负载并降低了性能。
connection con=null; String sql="select * from employee where id=5"; Statement st=conn.createStatement();
PreparedStatement :与Statement不同,PreparedStatement在创build时被赋予一个sql查询作为参数。
connection con=null; String sql="select * from employee where id=?"; PreparedStatement ps=conn.prepareStatement(sql);
这个sql语句被发送到编译它的数据库。 所以,在preparedStatement中编译只发生一次,但是在语句每次调用Statement时都会发生。
您始终可以使用PreparedStatement而不是Statment(select,插入,更新,删除)。 更好的性能和防止SQL注入。
但是,请不要使用dynamic请求,如使用WHERE variable IN [ hundreds possibilities ]
的请求:
-
这是有效的,你失去了性能和内存,因为每当新的请求caching时,PreparedStatement不仅仅是SQL注入,而是关于性能。 在这种情况下,Statement不会变慢。
-
你的游泳池有一个PreparedStatment的限制(-1默认,但你必须限制它),你会达到这个限制! 如果没有限制或非常大的限制,则存在内存泄漏的风险,在极端情况下会出现OutofMemory错误。 所以,如果是为3个用户使用的小型个人项目,这并不是什么戏剧性的,但是如果你在一家大公司,而且你的应用被千人和百万的请求所使用,那么你就不需要这么做了。
一些阅读。 IBM:使用预准备语句caching时的内存使用注意事项