簡體   English   中英

處理Java OOP風格的SQL數據庫連接的正確方法

[英]Proper way to handle SQL database connections in java OOP style

我最近遇到了編程挑戰。 公開用於管理虛擬電影租賃公司的API是一個OOP挑戰。 我選擇使用sparkjava,並使用heroku模板進行工作。 我已經在此處將代碼發布到Github上 ,並邀請任何人查詢README文檔中提供的URL。 秘密密碼是secret

對於需要改進的事情,我收到了很多很好的反饋。 一個反對意見是:

直接通過驅動程序處理連接,而無需進行任何正確關閉連接的處理。

所以我試圖弄清楚這意味着什么,為什么會出現問題,以及如何解決它並使我的代碼更好。

例如我在主類中有此方法:

public static int validate_customer(String cust) throws SQLException, URISyntaxException {
    int customer = 0;
    try{
        customer = Integer.parseInt(cust);
    }catch (Exception e){
        throw new SQLException("Invalid customer integer -> " + cust);
    }

    Connection connection = DatabaseUrl.extract().getConnection();
    PreparedStatement stmt = connection.prepareStatement("SELECT count(*) from customers where id = ?;");
    stmt.setInt(1, customer);
    ResultSet rs = stmt.executeQuery();
    rs.next();
    if ( rs.getInt(1) < 1 ){
        throw new SQLException("Invalid customer id -> " + customer);
    }
    rs.close();
    stmt.close();
    return customer;
}

為什么這是處理與數據庫交互的不正確方法? 主類中還有其他與DB交互的方法,但是該方法與本示例基本相同。

對我而言,如果與數據庫的連接存在問題,則將在以下行中發生: Connection connection = DatabaseUrl.extract().getConnection(); 並拋出一個SQLException 如果連接發生問題,並且查詢的某些部分不起作用,則此validate_customer方法將引發異常。 為什么這在我的代碼中有問題?

直接通過驅動程序處理連接

這意味着您沒有使用數據庫連接池(例如HikariCP ),這意味着有可能很快耗盡連接限制。 Heroku示例不使用數據庫連接池來限制示例中的依賴關系。

沒有適當關閉連接的任何處理。

這意味着stmt.close(); finally塊中不是,這意味着如果在方法中引發異常,則stmt將永遠不會關閉。

我經常在try catch的finally塊中看到關閉連接。 也許在try catch語句中的方法內部處理SQL Exception會更好,並且可以關閉finally塊中的資源。 這就是我經常看到的。 希望對您有所幫助。


為了對此進行更新,Java 7引入了一個名為“ try-with-resources”的功能。 這似乎是清理資源的新首選方式。 舉個例子:

try(Connection connection = Connection.getConnection();
    PreparedStatement stmt = connection.prepareStatement("..."))
{
    ...
}

嘗試使用資源將自動關閉實現AutoClosable接口並在try語句的括號中聲明的所有資源。

這是官方教程文檔的鏈接: https : //docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

我建議您使用數據源 在類路徑中,您具有數據源和特定於jdbc數據庫的驅動程序的依賴性。 在這種情況下,我使用的是dbcp2mysql

public long count(final int customerId) {

    int count;

    final String query = "SELECT count(*) FROM customers WHERE id = ?";

    try (final Connection conn = dataSource.getConnection();
         final PreparedStatement prepStatement = conn.prepareStatement(query)) {

        prepStatement.setInt(1, customerId);

        final ResultSet rs = prepStatement.executeQuery();

        rs.next();
        count = rs.getInt(1);

    } catch (SQLException e) {

        // You may want to log and throw a custom exception here.
        throw new RuntimeException(e);
    }

    return count;
}

public DataSource dataSource() {

    final org.apache.commons.dbcp2.BasicDataSource dataSource =
        new org.apache.commons.dbcp2.BasicDataSource();

    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl(environment.getProperty("jdbc:mysql://localhost:3306/myDatabase"));
    dataSource.setUsername(environment.getProperty("root"));
    dataSource.setPassword(environment.getProperty("password"));

    return dataSource;
}

注意,我沒有在finally塊上顯式關閉連接,因為自Java 7以來, ConnectionPreparedStatement是可自動關閉的資源

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM