我正在构建一个 Web 应用程序,在静态类和数据库之间使用单个(非池化)全职 (jdbc) 连接。预计这将是一个低流量站点,并且静态方法是同步的。为了加快对产品信息的访问速度,我第一次尝试PreparedStatements。当我在本地主机上进行测试时,确保我是唯一运行该应用程序的人。对我来说,很明显我的准备好的语句比我在该过程早期使用的未准备的语句慢。这可能不是一个公平的比较。未准备好的语句从一个表中获取单个结果集,然后就完成了。正如您从下面的代码中看到的,我对准备好的语句所做的涉及三个表和多个查询。但由于这是我第一次,我希望得到评论和评论。这确实有效;即所有数据均按预期检索。
下面的第一个方法 (initialize()) 在应用程序首次启动时从 servlet init() 方法调用一次。第二种方法 (getItemBatch()) 检索与产品名称 (Titel) 匹配的尽可能多的产品项的信息。我的小型开发/测试数据库包含不到 100 个(总计)项目,并且只有 1-3 个项目与每个名称匹配;最常见的是 1。服务器应用程序和数据库位于同一台计算机上,我通过本地主机从浏览器进行访问。与获取上面提到的主产品列表(所有项目)相比,对这些详细产品数据的持续明显等待令我感到惊讶。
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。我们的想法是创建它们一次(并且仅一次),并让它们永远可供所有用户使用(即直到应用程序或服务器关闭)。我想要一种伪存储过程。我会直接使用存储过程,但数据库的存在是为了支持另一个应用程序(他们的内部销售系统),并且我将使用它进行只读互联网销售......避免与他们的维护工作发生任何潜在的冲突或协议(protocol)等,不做任何改变他们的数据库设置。我建议我的应用程序使用仅限只读权限的新帐户。想想看,我还没有测试是否可以在该模式下使用准备好的语句;看起来应该可行。
每个结果集都在创建它们的方法的finally block 中关闭。我想这样可以吧?我对多个结果集(后两个)重复使用相同的 RS 变量名称,但仅关闭一次。可是等等!我还需要那个吗? ResultSets 在方法的范围内声明。如果在不关闭旧方法的情况下重置它们不会导致泄漏,那么退出该方法本身也应该起到同样的作用。它是一个静态方法,但每次使用时都会重置 ResultSet(至少)。因此,最多只有一组 ResultSet 句柄可供重用;不是失控的“泄漏”。
我想知道是否可以同时发送循环中的两个选择请求,只需将它们转换为一个用“;”分隔的准备好的语句即可。或者刚刚找到“MultipleActiveResultSets=True”;允许 SQL Server 在单个连接上处理多个事务请求的文档...仍在调查这一点。或者是否有另一种方法来创建一个准备好的语句,通过一次提交来获取所有数据? (在我看来,往返次数太多了。)最后,使用连接池可能会对我有所帮助,但我还没有这样做。目前它在我的项目中的优先级较低,但我可能必须在上线之前完成它。
最佳答案
如果您创建 Web 应用程序并使用 Tomcat、jetty 等 Web 容器,您始终可以使用 jdbc 数据源和连接池。很简单。很好的解释给出了 here
如果您不想使用连接池,我想最好使用上面链接中描述的方法范围连接
关于java - SQL 准备语句;我做对了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14535482/