網頁

2021/6/1

工作踩坑紀錄 20210601

晚上飯才剛煮好就被通知上線的程式有錯,趕緊遠端回去查log找問題。


最近在做遷移舊專案邏輯到新專案的工作,舊程式在查資料時是用JDBC PreparedStatementResultSet取得查詢結果,新專案要改為Spring Data JPA query method寫法。

舊專案的查詢結果可能會有多筆,但下面用if(rs.next())將游標(cursor)移到第一筆資料並生成物件的寫法讓我誤以為只會有一筆。

...
    String sql = "select * from product"
        + " where product_id = ? "
        + " and approved = 1 "
        + " order by create_date desc";

    PreparedStatement ps = connection.prepareStatement(sql);
    ps.setInt(1, productId);
    ResultSet rs = ps.executeQuery();
    if (rs.next()) { // 這裡用if讓我誤以為結果只會有一筆
        return new Product(rs);
    }
...

上面這個很適合拿來做面試題,「請問以上查詢結果的ResultSet有幾筆資料?」,答案是有多筆資料。


在新專案以Spring Data JPQ query method改寫只回傳單一物件如下,在查詢結果為多筆時導致NonUniqueResultException錯誤。

public interface ProductRepository extends JpaRepository<Product, Long> {
    ...
    Optional<Product> findByProductIdAndApproved(long productId, int approved);
    ...
}

修正為只取第一筆(top)資料如下解決。

public interface ProductRepository extends JpaRepository<Product, Long> {
    ...
    Optional<Product> findTopByProductIdAndApprovedOrderByCreateDateDesc(long productId, int approved);
    ...
}

其實這不是一個坑,而是我對理解程式的邏輯有誤造成此問題(寫程式五年多了還是會犯這種錯),因為從ResultSet取得資料時通常是用while(rs.next())。此外是上線後才發現錯誤,之前在UAT測試都未發現問題,因此要避免類似的問題的作法只有:

  1. 加強對程式的理解。
  2. 完整的測試案例。

沒有留言:

張貼留言