【问题标题】:Where to put the prepared statement OBJECTS in Java?在Java中将准备好的语句OBJECTS放在哪里?
【发布时间】:2012-08-28 00:00:06
【问题描述】:

我想使用准备好的语句。我已经读过准备好的语句的优点是它们不必每次都再次解析/编译,因此可以减少负载。现在我的问题是,在 Java 中还是在我的数据库系统中,已经准备好的语句的“识别”发生在哪里?我问,因为我想知道在我的代码中将我的 PreparedStatement 对象存储在哪里:作为类属性并为每个请求设置参数,或者在有请求时创建一个新的准备好的语句对象。

    public class Option1 {
       private PreparedStatement myStatement;
       public Option1() {
          // create the myStatement object
          myStatement = conn.prepareStatement("");
       }
       public List<Items> query() {
          // just use the myStatement object
          myStatement.setString(1, "foo");
       }
   }

    public class Option2 {
       public List<Items> query() {
          PreparedStatement myLocalStatement = conn.prepareStatement("");;
          // create and use the statement
          myLocalStatement.setString(1, "foo");
       }
   }

现在我的问题是,选项 1 或 2 更好的方法是什么?但是,我必须在每次执行后通过myStatement.close() 进行“清理”,对吗?

也许我应该换个方式问:如何以最有效的方式重用它?

更新:如果有两个答案,一个更喜欢选项 1 和一个选项 2,我恳请社区为他们的选择投票^^

【问题讨论】:

  • 不重复使用准备好的语句有什么用?
  • @Tichodroma 避免 SQL 注入(当然,还有其他方法可以达到同样的效果)
  • 问题是如何以最有效的方式重用它。
  • @Tichodroma 这就是我的观点 ;-) 因此,我问,数据库系统是否识别已经准备好的语句(字符串比较或其他),或者我是否必须通过使用相同的语句来处理这个问题对象......也许“preparedStatement()”的使用在查询被发送到数据库系统时添加了一个标志?!
  • 首先 - 不要盲目相信您阅读的建议。措施!一些数据库驱动程序在准备时会做很多工作,以至于需要对准备好的语句进行数百次调用才能完成工作。

标签: java jdbc prepared-statement


【解决方案1】:

我会选择选项 1:即。

public class Option1 {
       private PreparedStatement myStatement;
       public Option1() {
          // create the myStatement object
          myStatement.setString(1, "foo");
       }
       public List<Items> query() {
          // just use the myStatement object
       }
   }

原因: 我可以在需要时为其分配新对象。通过做这样的事情

pst = con.prepareStatement(myQuery); 在函数中,在您的情况下,函数将是 Option1()

【讨论】:

    【解决方案2】:

    我会推荐选项 2

    public class Option2 {
       public List<Items> query() {
          PreparedStatement myLocalStatement = conn.prepareStatement("");;
          // create and use the statement
          myLocalStatement.setString(1, "foo");
       }
    }
    

    因为如果逻辑单元分布在多个方法和数据成员中,故障点会增加并且容易出错。

    或者我愿意:

    public class Option2 {
       public List<Items> query(String sql, String parameter) {
          PreparedStatement myLocalStatement = conn.prepareStatement(sql);
          // create and use the statement
          myLocalStatement.setString(1, parameter);
       }
    }
    

    并像这样使用它:

    Option2 myQuery = new Option2();
    myQyery.query("SELECT * FROM PERSON WHERE NAME = :?","ANY_NAME");
    

    【讨论】:

      【解决方案3】:

      SQL 数据库正在缓存以完整查询(包括where 子句)为键的语句的执行计划。通过使用准备好的语句,查询是相同的,无论您使用什么值(它们总是'?')。

      因此,从数据库缓存的角度来看,您的两个选项之间没有区别。请参阅 this article,其中还描述了一些 Java EE 特定问题。

      但是,从代码的角度来看,当然还有其他一些因素,正如其他人所提到的,尤其是当您经常重用它时(例如在 this example 中)。重要的是,一些 JDBC 驱动程序支持precompilation
      请记住,准备好的语句最初会增加开销,同时赶上每次后续使用 - 这是great chapter about that

      【讨论】:

        【解决方案4】:

        就个人而言,我喜欢第二种选择,这就是我的想象

        public void addAccount(String username, String password, String name) {
        String query="INSERT INTO Accounts (username, password, name) VALUES (?,?,?)";
        try(Connection connection = dataSource.getConnection()) {
          try(PreparedStatement statement = connection.preparedStatement(query)){
             statement.setString(1, username);
             statement.setString(2, password);
             statement.setString(3, name);
             statement.executeUpdate();
          }
         } catch(SQLException e) {
          e.printStacktrace();
         }
        

        之所以应该使用 try-with-resource 只是因为它可以处理常见的编码错误,例如发生错误时关闭。这也保证了执行后,您的语句/连接/结果集将被关闭(或任何其他问题)

        【讨论】:

          猜你喜欢
          • 2010-12-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-18
          • 2018-09-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多