单个 Try Catch 块中的多个 JDBC 语句。是好习惯吗?
Posted
技术标签:
【中文标题】单个 Try Catch 块中的多个 JDBC 语句。是好习惯吗?【英文标题】:Multiple JDBC Statements in Single Try Catch Block. is it Good Practice? 【发布时间】:2017-04-25 06:27:31 【问题描述】:我是 Java 新手,我的工作都与 JDBC 相关——关于插入和处理数据。总的来说它工作正常。
为了减少代码,我使用单个try catch()
block 来编写多个JDBC
Statements
和Prepared Statements
。
示例代码:
public void dashboardReports()
try
String total_stock_value="select sum(price*closingstock)as tsv from purchase_table";
Statement ps_tsv=connection.createStatement();
ResultSet set_tsv=ps_tsv.executeQuery(total_stock_value);
if(set_tsv.next())
total_stock.setText(set_tsv.getString("tsv"));
String tota_sales="select sum(INVOICE_VALUE) as iv from PARTYWISE_ACCOUNTS_LEDGER";
Statement st_total_sales=connection.createStatement();
ResultSet set_total_sales=st_total_sales.executeQuery(tota_sales);
if(set_total_sales.next())
total_sales.setText(set_total_sales.getString("iv"));
String total_purchases="select sum(CP_INVOICEVALUE)as cpi from COMPANY_PAYMENTS";
Statement st_tps=connection.createStatement();
ResultSet set_tps=st_tps.executeQuery(total_purchases);
if(set_tps.next())
total_purchases_label.setText(set_tps.getString("cpi"));
String total_collectionss="select sum(PAYMENT_REC) as payrec from PARTYWISE_ACCOUNTS_LEDGER";
Statement ps_toco=connection.createStatement();
ResultSet set_toco=ps_toco.executeQuery(total_collectionss);
if(set_toco.next())
total_collections.setText(set_toco.getString("payrec"));
String total_payments="select sum(CP_PAYMENTREC) as paid from COMPANY_PAYMENTS";
Statement ps_topa=connection.createStatement();
ResultSet set_topa=ps_topa.executeQuery(total_payments);
if(set_topa.next())
total_payments_label.setText(set_topa.getString("paid"));
catch (Exception e)
// TODO: handle except
那么这是处理的好方法还是其他方法?
到目前为止,我的代码运行良好,这种方法将来会不会出现问题。
【问题讨论】:
如果此代码运行良好,您应该将其提交到我们的Code Review 姊妹网站。 我看到的最大问题是你没有关闭你的资源,如果你使用 try-with-resources 问题会更小,你会自动使用更小的范围 try-块。顺便说一句:您的代码效率低下:您查询 2 个表 2 次,而您只能查询这两个表一次。 【参考方案1】:这违反了Single Responsbility 和Single Layer of Abstraction 原则。
所以尽管这段代码在技术上是有效的;您不仅应该关注它的正确性,还应该关注它的可读性。和可测试性。而且我认为您所显示的输入中的任何一个都不是“很棒”。
因此;从干净的代码(质量)角度来看;我宁愿建议按照以下方式去做:
outer method ...
try
helperMethod1();
helperMethod2();
catch( ...
为您遇到的每种不同情况提供一个小助手。当然,您不会止步于此;但尝试隔离这些助手的共同方面;并且可能找到使用单个更通用帮助器的方法。
当然:如果可能的话,你尽量避免捕获Exception。相反,您可能会捕获最具体的异常!
【讨论】:
+1 我同意你的说法,甚至想补充一点,因为helperMethod1
和 helperMethod2
在功能上几乎相同,它们可以重构为单个参数化方法
好主意。考虑到我的答案。
@GhostCat:如何确保在此链接中的交易嵌套尝试块的情况下编码干净 - ***.com/a/30116055/4358787
@gaurav 干净的代码说:单层抽象。在干净的代码中,没有嵌套。如果有的话,你有方法 A,它在一个 try 块中调用方法 B,而 B 在另一个 try 块中调用 C。【参考方案2】:
由于您在这里只进行SELECT
操作,因此没有真正需要显式事务,因为您没有更改数据库的状态,也没有什么可以回滚的。将所有 SELECT
语句分组到单个 try
块中并没有错。但是,有一个潜在的缺点,即如果一个 SELECT
失败,您的代码将退出该 try
块并且所有后续查询都不会运行。如果你能容忍这一点,那么你可以保持原样。与此类似的是一系列串联的灯泡。如果一个坏了,那么他们都出去了。
您所拥有的另一种方法是为每个查询使用单独的 try
块。然后,即使其中一个发生异常,其他人也有可能成功完成。这里的类比是并联电路中的一系列灯泡。
【讨论】:
【参考方案3】:我认为你的代码没问题。 最后需要在块中关闭结果集、语句和连接。
【讨论】:
【参考方案4】:如果您对所有后续 SELECT
s 失败感到满意,那么我会更改方法以引发异常
public void dashboardReports() throws SQLException
....
然后从调用方法中捕获 SQLException。
注意我认为抛出/捕获SQLException
比Exception
更好
【讨论】:
和我刚才写的有点相似……欢迎反馈。【参考方案5】:只要确保关闭语句和结果集即可:
try
String total_stock_value="select sum(price*closingstock)as tsv from purchase_table";
try (Statement ps_tsv=connection.createStatement();
ResultSet set_tsv=ps_tsv.executeQuery(total_stock_value))
if(set_tsv.next())
total_stock.setText(set_tsv.getString("tsv"));
String tota_sales="select sum(INVOICE_VALUE) as iv from PARTYWISE_ACCOUNTS_LEDGER";
try (Statement st_total_sales=connection.createStatement();
ResultSet set_total_sales=st_total_sales.executeQuery(tota_sales))
if(set_total_sales.next())
total_sales.setText(set_total_sales.getString("iv"));
String total_purchases="select sum(CP_INVOICEVALUE)as cpi from COMPANY_PAYMENTS";
try (Statement st_tps=connection.createStatement();
ResultSet set_tps=st_tps.executeQuery(total_purchases))
if(set_tps.next())
total_purchases_label.setText(set_tps.getString("cpi"));
String total_collectionss="select sum(PAYMENT_REC) as payrec from PARTYWISE_ACCOUNTS_LEDGER";
try (Statement ps_toco=connection.createStatement();
ResultSet set_toco=ps_toco.executeQuery(total_collectionss))
if(set_toco.next())
total_collections.setText(set_toco.getString("payrec"));
String total_payments="select sum(CP_PAYMENTREC) as paid from COMPANY_PAYMENTS";
try (Statement ps_topa=connection.createStatement();
ResultSet set_topa=ps_topa.executeQuery(total_payments))
if(set_topa.next())
total_payments_label.setText(set_topa.getString("paid"));
catch (Exception e)
// TODO: handle except
【讨论】:
【参考方案6】:1.您可以使用executeQuery(Connection conn, Statement st, String sql)
之类的方法来封装和减少您的代码行数。
2.不要依赖泛型Exception
,也要捕获sql特定的异常类
3.我没有看到finally
阻止正确关闭资源,除非您在其他地方这样做。或者,您可以尝试使用try with resource 语法来消除对finally
块的需要
4.在catch
块中查看您需要做什么 - 您需要将异常向上传播到链上方还是在该处使程序失败?
5.在我看来,ResultSet
和 Statement
需要尽可能短,因此请尝试尽快关闭它们 - 不要等待将它们全部关闭。第 1 点将有助于实现这一目标。
从技术正确性和有效性的角度来看,以您的方式编写代码并没有什么害处——对所有 SQL 使用单个 try-catch 并排除任何异常(因为我在那里只看到 SELECT
sqls)但是有干净、可读和可维护的代码,在这方面,你的代码看起来很糟糕。
【讨论】:
【参考方案7】:尽管您的代码可以工作,但我强烈建议重构它以获得更好的维护和可读性,如下所示。另外,请确保正确关闭资源:
public void dashboardReports()
handleTotalStocks();
handleTotalSales();
handleTotalPurchages();
//Add others
handleTotalStocks() 方法:
private void handleTotalStocks()
String total_stock_value="select sum(price*closingstock)as tsv
from purchase_table";
try(Statement ps_tsv=connection.createStatement();
ResultSet set_tsv=ps_tsv.executeQuery(total_stock_value);)
if(set_tsv.next())
total_stock.setText(set_tsv.getString("tsv"));
//add other methods
【讨论】:
【参考方案8】:更好的方法是创建执行常见操作的方法:
public String execute(String query) throws SQLException
Statement ps_toco=connection.createStatement();
ResultSet set_toco=ps_toco.executeQuery(query);
return set_toco.next();
当你调用这个方法时,用 try catch 块包围它。
【讨论】:
以上是关于单个 Try Catch 块中的多个 JDBC 语句。是好习惯吗?的主要内容,如果未能解决你的问题,请参考以下文章
java中的“try - catch -finally”结构中的“finally”都有哪些用途