单个 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 StatementsPrepared 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 我同意你的说法,甚至想补充一点,因为 helperMethod1helperMethod2 在功能上几乎相同,它们可以重构为单个参数化方法 好主意。考虑到我的答案。 @GhostCat:如何确保在此链接中的交易嵌套尝试块的情况下编码干净 - ***.com/a/30116055/4358787 @gaurav 干净的代码说:单层抽象。在干净的代码中,没有嵌套。如果有的话,你有方法 A,它在一个 try 块中调用方法 B,而 B 在另一个 try 块中调用 C。【参考方案2】:

由于您在这里只进行SELECT 操作,因此没有真正需要显式事务,因为您没有更改数据库的状态,也没有什么可以回滚的。将所有 SELECT 语句分组到单个 try 块中并没有错。但是,有一个潜在的缺点,即如果一个 SELECT 失败,您的代码将退出该 try 块并且所有后续查询都不会运行。如果你能容忍这一点,那么你可以保持原样。与此类似的是一系列串联的灯泡。如果一个坏了,那么他们都出去了。

您所拥有的另一种方法是为每个查询使用单独的 try 块。然后,即使其中一个发生异常,其他人也有可能成功完成。这里的类比是并联电路中的一系列灯泡。

【讨论】:

【参考方案3】:

我认为你的代码没问题。 最后需要在块中关闭结果集、语句和连接。

【讨论】:

【参考方案4】:

如果您对所有后续 SELECTs 失败感到满意,那么我会更改方法以引发异常

public void dashboardReports() throws SQLException 

 ....

然后从调用方法中捕获 SQLException。

注意我认为抛出/捕获SQLExceptionException 更好

【讨论】:

和我刚才写的有点相似……欢迎反馈。【参考方案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.在我看来,ResultSetStatement 需要尽可能短,因此请尝试尽快关闭它们 - 不要等待将它们全部关闭。第 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中的异常

java中的“try - catch -finally”结构中的“finally”都有哪些用途

Nodejs:catch块中的回调函数在try-catch中返回未定义的参数

try/catch/finally

Try-Catch-Finally代码块中的return

在catch块中捕获异常后,是否可以再次在try块中执行代码?