4

我有一个数据库日志附加程序,它每隔一段时间将可变数量的日志行插入数据库。

我想以一种防止 SQL 注入的方式创建一个 SQL 语句,但不使用服务器端准备好的语句(因为我在每个选择中都有可变数量的行,缓存它们无济于事,但可能会损害这里的性能) .

我也喜欢准备好的语句的便利性,并且更喜欢它们而不是字符串连接。是否有类似“客户端准备好的声明”之类的东西?

4

6 回答 6

7

听起来您还没有对最简单的解决方案进行基准测试 - 准备好的语句。您说它们“可能会损害性能”,但在您对其进行测试之前,您真的不会知道。

肯定会先测试准备好的语句。即使它们确实会稍微影响性能,但在您对它们进行测试之前,您不会知道您是否仍能达到您需要的性能。

当您还没有尝试过最明显的解决方案时,为什么还要花时间寻找替代解决方案?

如果您发现准备好的语句执行计划缓存成本很高,您可能会发现有一些特定于 DB 的方法可以调整或禁用它。

于 2009-08-06T13:15:38.317 回答
2

不确定我是否正确理解了您的问题。有什么PreparedStatement不符合您的需求吗?

我认为语句是否缓存在服务器端是数据库驱动程序和您正在使用的特定数据库的实现细节;如果您的查询/语句随着时间的推移发生变化,那么这应该没有影响 - 缓存/编译的语句根本不会被使用。

于 2009-08-06T13:15:14.637 回答
2

首先,Jon 的回答是,您应该采用最明显的解决方案,直到性能被衡量为一个问题,这通常是正确的方法。

我不认为您对性能的担忧是错误的。我当然已经看到预编译的复杂语句在性能规模上(在 MS-SQL 2000 上)显着失败。原因是语句太复杂了,根据参数它有几个潜在的执行路径,但是编译锁定了一组参数,下一组参数太慢,而重新编译会强制重新计算执行计划更适合不同的参数集。

但是,在您在实践中看到它之前,这种担忧是非常牵强的。

这里的根本问题是参数转义是特定于数据库的,因此除非数据库的 JDBC 驱动程序为您提供了非标准的东西(极不可能),否则您将不得不拥有不同的库或不同的转义机制非常特定于这一数据库。

从您问题的措辞来看,您的性能问题似乎还没有达到值得寻找(或开发)这样一个解决方案的地步。

还应该注意的是,尽管 JDBC 驱动程序可能并非都以这种方式运行,但从技术上讲,根据规范,预编译应该缓存在 PreparedStatement 对象中,如果你把它扔掉并每次都得到一个新的 PreparedStatement,它不应该实际上是在缓存任何东西,所以整个问题可能是无声的,需要针对您的特定 JDBC 驱动程序进行调查。

从规范:

带或不带 IN 参数的 SQL 语句可以预编译并存储在 PreparedStatement 对象中。然后可以使用该对象多次有效地执行该语句。

于 2009-08-06T14:01:23.440 回答
0

使用常规准备好的语句有什么问题,例如在以下伪代码中:

DatabaseConnection connection;
PreparedStatement insertStatement = ...;

    ...

connection.beginTransaction();
for (Item item : items)
{
   insertStatement.setParameter(1, item);
   insertStatement.execute();
}
connection.commitTransaction();

智能数据库实现会将多个插入批处理到与数据库服务器的一个通信交换中。

于 2009-08-06T13:35:46.730 回答
0

我想不出你不应该使用准备好的语句的原因。如果您在使用连接池的 J2EE 服务器上运行它,则服务器会保持您的连接打开,并且服务器会缓存您的访问/执行计划。这不是它缓存的数据!

如果您每次都关闭连接,那么您可能不会获得任何性能。但是您仍然可以获得 SQL 注入预防

大多数 Java 性能调优书籍都会告诉您相同的内容: Java 性能调优

于 2009-08-06T13:37:34.030 回答
-1

准备好的语句不关心客户端或服务器端。

使用它们并删除任何 SQL 字符串连接。没有一个理由不使用准备好的语句。

于 2009-08-06T13:47:03.707 回答