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

Joh*_*nna 27 java database prepared-statement

我知道使用的优点PreparedStatement,这些都是

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

但我想知道我们何时使用它而不是Statement

Mar*_*oth 29

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

    如果不使用预准备语句,则数据库服务器必须解析,并在每次运行时为该语句计算执行计划.如果您发现您将多次运行相同的语句(使用不​​同的参数),那么它值得准备一次语句并重新使用该预准备语句.如果您正在查询数据库adhoc,那么这可能没什么好处.

  2. 防止SQL注入

    这是您几乎总是想要的优势,因此PreparedStatement每次使用都是一个很好的理由.它是必须参数化查询的结果,但它确实使运行它更安全.我唯一能想到的是,如果您允许adhoc数据库查询,这将没有用; 如果您正在为应用程序进行原型设计并且它更快,或者查询不包含任何参数,则可以简单地使用Statement对象.


mat*_*mes 17

问汤姆的意见:

在JDBC中使用Statement应该100%本地化以用于DDL(ALTER,CREATE,GRANT等),因为这些是唯一不能接受BIND VARIABLES的语句类型.

PreparedStatements或CallableStatements应该用于其他类型的语句(DML,查询).因为这些是接受绑定变量的语句类型.

这是一个事实,一个规则,一个法律 - 使用准备好的陈述无处不在.使用STATEMENTS几乎没有.

他特别谈论Oracle,但同样的原则适用于任何缓存执行计划的数据库.

同时扩展和防止SQL注入攻击的数据库应用程序?有什么缺点?


Nei*_*fey 9

我会转向这一轮:在一个公开发布的应用程序中,你通常应该总是使用准备好的语句,除非你有一个非常令人信服的理由不应该,并且你应该总是"准备"参数准备好的语句,而不是通过将它们拼接到请求参数.

为什么?好吧,基本上是因为你给出的原因(或者至少是第二个)......

  • 注意:PreparedStatement的性能可能很糟糕,除非您使用它执行_lots_操作.这是依赖于数据库驱动程序 (3认同)

Wol*_*ang 5

在WHERE子句中应该非常小心地使用PreparedStatements.

假设一个表定义为:

create table t (int o, k varchar(100), v varchar(100))
Run Code Online (Sandbox Code Playgroud)

(例如"o:object-ID(外键),k:attribute-key,v:attribute-value").

此外,v上有一个(非唯一的)索引.

create index ixt on t ( v )
Run Code Online (Sandbox Code Playgroud)

假设此表包含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));
}
Run Code Online (Sandbox Code Playgroud)

("因此,每个对象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=?
Run Code Online (Sandbox Code Playgroud)

("查找具有两个给定属性的对象")

我对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'
Run Code Online (Sandbox Code Playgroud)

("SQL-Server将始终首先搜索v ='1234',然后搜索v ='v1'")

关心
沃尔夫冈