SQL PreparedStatement;我做得对吗?

时间:2013-01-26 09:15:23

标签: java sql sql-server jdbc prepared-statement

我正在使用静态类和数据库之间的单个(非池化)全时(jdbc)连接构建Web应用程序。预计这将是一个低流量站点,并且静态方法是同步的。为了加快产品信息的访问速度,我第一次尝试PreparedStatements。在我测试的时候,在localhost上,确定我是唯一运行该应用程序的人。我觉得我准备好的语句比我之前在这个过程中使用的毫无准备的语句要慢。这可能不是一个公平的比较。未准备好的语句从一个表中获得单个结果集,并且已完成。从下面的代码中可以看出,我对预处理语句的处理涉及三个表和多个查询。但由于这是我的第一次,我希望得到评论和评论。这确实有效;即按预期检索所有数据。

首次启动应用程序时,从servlet init()方法调用下面的第一个方法(initialize())。第二种方法(getItemBatch())检索有关与产品名称(Titel)匹配的产品项目的信息。我的小开发/测试数据库的项目少于100个(总计),每个名称只有1-3个项目;通常只有1.服务器应用程序和数据库在同一台机器上,我通过localhost从浏览器访问。与获取上面提到的主产品列表(所有项目)相比,我对这个详细的产品数据的持续感知等待感到惊讶。

  public static boolean initialize (Connection connArg, String dbNameArg, String dbmsArg) {

    con = connArg;
    dbName = dbNameArg;
    dbms = dbmsArg;
    sqlserver_con = connArg;

    ItemBatchStatement =
          "select Cartnr, Hgrupp, Prisgrupp, Moms from dbo.Centralartregister " +
           "where Titel = ?";

    ForArtNrStatement =
          "select Artnr, Antal from dbo.Artikelregister " +
           "where Cartnr = ? and Antal > 0";

    ItemHgruppStatement =
            "select Namn from dbo.Huvudgrupper " +
             "where Hgrupp = ?";

    try {
      con.setAutoCommit(false);
      getItemBatch = con.prepareStatement(ItemBatchStatement);
      getForArtNr = con.prepareStatement(ForArtNrStatement);
      getItemHgrupp = con.prepareStatement(ItemHgruppStatement);
    } catch (SQLException e) {
      return(false);
    } finally {
      try {con.setAutoCommit(true);} catch (SQLException e) {}
    }
    return(true);
  }

-

  public static synchronized String getItemBatch (String Titel) throws SQLException {

    String ret_xml;
    ResultSet rs  = null;
    ResultSet rs1 = null;
    ResultSet rs2 = null;

    Titel = charChange(Titel);
    ret_xml = "<ItemBatch Titel='" + Titel + "'>";
    try {
      con.setAutoCommit(false);
      getItemBatch.setString(1,Titel);
      rs = getItemBatch.executeQuery();
      while (rs.next()) {
        getForArtNr.setInt(1,rs.getInt("Cartnr"));
        rs1 = getForArtNr.executeQuery();
        getItemHgrupp.setInt(1,rs.getInt("Hgrupp"));
        rs2 = getItemHgrupp.executeQuery();
        if (rs1.next() && rs2.next()) {
          ret_xml += "<item><Hgrupp>" + rs2.getString("Namn") + "</Hgrupp><Price>" + rs.getInt("Prisgrupp") + "</Price><Moms>" + rs.getInt("Moms") + "</Moms><Cartnr>" + rs.getInt("Cartnr") + "</Cartnr><Artnr>" + rs1.getInt("Artnr") + "</Artnr></item>";
        }
      }
      ret_xml += "</ItemBatch>";
      return(ret_xml);
    } catch (SQLException e) {
      return("SQLException: " + e);
    } finally {
      try {con.setAutoCommit(true);} catch (SQLException e) {}
      if (rs != null) {rs.close();}
      if (rs1 != null) {rs1.close();}
      if (rs2 != null) {rs2.close();}
    }
  }

更新:我仍在谷歌搜索并寻找更好的方法。我想补充一点供你考虑。

我正在通过servlet的destroy()方法关闭准备好的语句;调用上面的方法“initialize()”以创建它们的相同servlet。我们的想法是创建它们一次(并且只创建一次)并让它们永远可供所有用户使用(即直到应用程序或服务器关闭)。我正在寻找一种伪存储过程。我只是直接使用存储过程,但数据库存在以支持另一个应用程序(他们的内部销售系统),我将用它来进行只读的互联网销售...避免与维护工作的任何潜在冲突通过不做任何改变他们的数据库设置的事情或协议等。我建议我的应用使用限制为只读权限的新帐户。并且考虑到这一点,我还没有测试过我是否可以在该模式下使用Prepared Statements;看起来应该有用。

每个结果集在创建它们的方法的finally块中关闭。我猜那没关系?我为多个结果集重复使用相同的RS变量名(在后两个上),但只关闭一次。可是等等!我甚至需要吗? ResultSets在方法范围内声明。如果重置它们而不关闭旧的那些不会导致泄漏,那么退出该方法应该自己做同样的事情。它是一个静态方法,但ResultSet每次使用时都会重置(至少)。因此,最多只有一组ResultSet句柄可供重用;不要逃避“泄漏”。

我想知道我是否可以同时在循环中发送两个选择请求,只需将它们转换为由';'分隔的一个预准备语句。或者只是找到“MultipleActiveResultSets = True”;允许SQL Server在单个连接上处理多个事务请求的文档......仍在调查此问题。或者是否有另一种方法来创建一个准备好的语句,通过一次提交来获取所有数据? (对我而言似乎有太多的往返。)最后,我可能会使用连接池来提升,我还没有完成。它现在在我的项目中是低优先级的,但在我们上线之前我可能不得不这样做。

1 个答案:

答案 0 :(得分:1)

如果您创建Web应用程序并使用某些Web容器(如tomcat,jetty等),则始终可以使用jdbc数据源和连接池。很简单。好的解释给出了here

如果您不想使用连接池,我认为最好使用上面链接描述的方法范围连接