我们什么时候应该使用PreparedStatement而不是Statement?

时间:2010-01-20 06:23:28

标签: java database prepared-statement

我知道使用PreparedStatement的优点,

  • 查询由数据库服务器重写和编译
  • 防止SQL注入

但我想知道何时使用它代替Statement

8 个答案:

答案 0 :(得分:26)

  1.   

    查询由数据库服务器重写和编译

    如果你不使用准备好的 声明,数据库服务器将 必须解析,并计算一个 声明的执行计划 每次运行它。如果你找到了 你将运行相同的声明 多次(有不同的 参数)然后它值得准备 声明一次并重复使用 准备好的声明如果你是 然后查询数据库adhoc 可能没什么好处 此

  2.   

    防止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 ]的请求:

  1. 它适得其反,你失去了性能和内存,因为每次新请求都会缓存,而PreparedStatement不只是用于SQL注入,而是关于性能。在这种情况下,Statement不会慢。

  2. 您的游泳池有一个PreparedStatment限制(-1 defaut但你必须限制它),你将达到这个限制!如果你没有限制或非常大的限制你有一些内存泄漏的风险,并在极端情况下OutofMemory错误。因此,如果它适用于3个用户使用的小型个人项目,那么它并不具有戏剧性,但如果您是一家大公司并且您不想要这样做,那么您就不会想要这样做了。应用程序被千人和百万请求使用。

  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时,应该基于您对特定数据库服务器的实际经验/实验。