簡體   English   中英

Java JDBC Select 語句是否應該始終位於 ZAD5D946E0C8E258E8023C796FZ 塊中?

[英]Should Java JDBC Select statements always be in a Try-Catch block?

將所有 Java JDBC Select 語句放入 ZA75131CB1C90FC1C0AZ52 塊中是否是一種好習慣? 目前我在沒有它的情況下編寫了大部分代碼。 但是,我使用 try-catch 進行插入/更新/刪除。

注意:當前使用 Sprint Boot。

String sqlQuery = "Select productId, productName, productStartDate from dbo.product where productId = 5"

public getProductData() {
    ....
    List<Product> productList =  namedJdbcTemplate.query(sqlQuery, new ProductMapper());

首先,如果您使用的是原始 JDBC API,則應始終使用PreparedStatement

是的,您只需要在某個時候用 try-catch 塊包裝代碼,盡管立即或在邏輯上適合的地方捕獲異常是一種很好的做法。 In case of SQL queries, you actually should wrap all of them into some Service class that will give you an access to modify your database objects without running through JDBC API every time. 例如:

public class UserService {
    private static final String CREATE_USER_SQL = "...";
    private final Connection jdbcConnection;

    public @Nullable User createUser(final String name) {
        try (final PreparedStatement stmt = jdbcConnection.prepareStatement(CREATE_USER_SQL)) {
            jdbcConnection.setAutoCommit(false);
            stmt.setString(1, name);
            stmt.executeQuery();
            jdbcConnection.commit();
            return new User(name);
        } catch (final SQLException createException) {
            System.out.printf("User CREATE failed: %s\n", createException.getMessage());
            try {
                jdbcConnection.rollback();
            } catch (final SQLException rollbackException) {
                System.out.printf("Rollback failed: %s\n", rollbackException.getMessage());
            }
            return null;
        }
    }
}

這立即解決了兩個問題:

  1. 您無需將樣板代碼 JDBC 代碼放在任何地方;

  2. 它將立即記錄任何 JDBC 錯誤,因此您無需通過復雜的調試過程來記錄 go。

由於這個問題被標記為spring-boot並且您使用的是 JdbcTemplate,因此我給您一個 Spring 特定的答案。

Spring 的要點之一是避免開發人員的樣板。 如果您發現自己重復添加內容,例如將 try-catch 塊放置在執行 DML 的代碼周圍,那么就會懷疑您做錯了什么。 使用 Spring 在代碼中添加自己的 try-catch 並不總是錯誤的,但通常是錯誤的。

SpringJdbc 為您處理了很多事情。 它處理關閉 JDBC 資源並將連接返回到它們的池,並將異常從 SQLException 轉換為未經檢查的 DataAccessExceptions 的層次結構。 在 Spring 中,包裝在事務代理中的方法拋出的未經檢查的異常會導致事務回滾。 如果您執行自己的 try-catch 邏輯,則可以防止在需要時發生回滾,如果您捕獲異常並且代理永遠不會看到它。

確實需要在某個地方捕獲異常。 在 Spring web 應用程序中,您可以設置一個異常處理程序來捕獲從 controller 層拋出的任何內容,以便您記錄它。 拋出異常是為了逃避無法處理問題的當前上下文,並將控制權重新定位到安全的地方。 對於大多數來自 JDBC 的異常,它們不是您可以修復的,您只想讓它被拋出,讓當前事務回滾,然后讓中央異常處理程序捕獲並記錄它。

如果您使用 JDBC 進行查詢,則 DB 層代碼的 Try-catch 很重要。

想一想,如果連接中斷了怎么辦? 或者如果數據庫崩潰了怎么辦? 或者出現其他一些不幸的情況。

對於這些事情,我建議您始終將 DB 層代碼保留在 try-catch 內。

還建議您有一些后備機制以防上述事件。

簡要說明:

  1. 首先,任何涉及 I/O 訪問的資源(數據庫訪問就是 I/O 訪問)必須始終關閉,否則會導致memory 泄漏
  2. 其次,最好依靠try-with-resources來關閉任何資源,因為必須手動調用.close()方法總是面臨由於潛在的Exception /運行時RuntimeException / Error而無法在運行時有效執行的風險被提前扔掉; 即使在finally方法中關閉資源也是不可取的,因為與 try-with-resources 相比,這樣的塊在不同的階段執行 - try-with-resources的自動關閉發生在try塊的末尾,而finally在所有try / catch塊的結束 - 除了它不是安全解決方案的基本問題之外,因為即使在finally塊內也可能發生throw ,從而阻止它正確完成。

這就是說,你總是需要關閉:

  1. Statement / PreparedStatement / CallableStatement
  2. 任何ResultSet
  3. 當您不再需要數據庫訪問時,整個Connection

您應該始終使用 try cactch 來處理它。

原因:例如,您開始連接到 db,然后發生了一些異常,如果您不回滾事務,它會留在 db 上並且性能會降低,並且會發生 memory 泄漏。

想象一下,如果您的連接限制是 100 並且在事務開始后拋出 100 異常並且您沒有回滾它,您的系統將被鎖定,因為您無法創建與數據庫的任何新連接。

但是,如果您想要“try catch finally”的替代方法,您可以這樣使用:

EmUtil.consEm(em -> {
    System.out.println(em.createNativeQuery("select * from temp").getResultList().size());
});

源代碼:

public final class EmUtil {

    interface EmCons {
        public void cons(EntityManager em);
    }

    public static void consEm(EmCons t) {
        EntityManager em = null;
        try {
            em = getEmf().createEntityManager();
            t.cons(em);
        } finally {
            if (em != null && em.getTransaction().isActive())
                em.getTransaction().rollback();
            if (em != null && em.isOpen())
                em.close();
        }
    }

    private static EntityManagerFactory getEmf() {
        //TODO
    }
   
}

Spring 將這些異常轉換為DataAccessException (更多詳細信息鏈接)。 捕獲這些異常會很好,您可以使用@Transactional回滾。

暫無
暫無

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

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