JdbcTemplate queryForInt / Long không được dùng nữa trong Spring 3.2.2. Nó nên được thay thế bằng gì?


104

Các phương thức queryforInt / queryforLong trong JdbcTemplate không được chấp nhận trong Spring 3.2. Tôi không thể tìm hiểu lý do tại sao hoặc điều gì được coi là phương pháp hay nhất để thay thế mã hiện có bằng các phương pháp này.

Một phương pháp điển hình:

int rowCount = jscoreJdbcTemplate.queryForInt(
    "SELECT count(*) FROM _player WHERE nameKey = ? AND teamClub = ?",
    playerNameKey.toUpperCase(),
    teamNameKey.toUpperCase()
);

OK, phương thức trên cần được viết lại như sau:

Object[] params = new Object[] { 
   playerNameKey.toUpperCase(), 
   teamNameKey.toUpperCase()
};
int rowCount = jscoreJdbcTemplate.queryForObject(
    "SELECT count(*) FROM _player WHERE nameKey = ? AND teamClub = ?",
    params, Integer.class);

Rõ ràng là việc không dùng nữa này làm cho lớp JdbcTemplate trở nên đơn giản hơn (hay không?). QueryForInt luôn là một phương thức tiện lợi (tôi đoán vậy) và đã có từ lâu. Tại sao nó đã bị loại bỏ. Do đó, mã trở nên phức tạp hơn.


Chi tiết này các phương thức không được dùng nữa: static.springsource.org/spring/docs/current/javadoc-api/…
Dan MacBean

Bạn nói đúng, tôi không biết tại sao nguồn của tôi không có@Deprecated
Sotirios Delimanolis

Cập nhật phiên bản mùa xuân đến 3.2.2 - vì nó có vẻ như nó đầu tiên bị phản đối ở đây
Dan MacBean

Tôi đã nâng cấp cơ sở mã hiện có từ 3.1 lên 3.2.2 và các phương pháp này được sử dụng khắp nơi. Cần hiểu lý do và cách cập nhật mã.
Dan MacBean

Lưu ý rằng queryForObject có thể trả về null(không phải trường hợp trong ví dụ của bạn). Tôi không tìm thấy cách nào khác ngoài việc sao chép mã kiểm tra rỗng từ queryForInt / Long.
hochraldo

Câu trả lời:


110

Điều tôi nghĩ là ai đó đã nhận ra rằng các phương thức queryForInt / Long có ngữ nghĩa khó hiểu, nghĩa là từ mã nguồn JdbcTemplate, bạn có thể thấy cách triển khai hiện tại của nó:

@Deprecated
public int queryForInt(String sql, Object... args) throws DataAccessException {
    Number number = queryForObject(sql, args, Integer.class);
    return (number != null ? number.intValue() : 0);
}

điều này có thể khiến bạn nghĩ rằng nếu tập kết quả trống, nó sẽ trả về 0, tuy nhiên, nó ném ra một ngoại lệ:

org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

vì vậy cách triển khai sau đây về cơ bản tương đương với cách triển khai hiện tại:

@Deprecated
public int queryForInt(String sql, Object... args) throws DataAccessException {
    return queryForObject(sql, args, Integer.class);
}

Và sau đó mã không còn được dùng nữa bây giờ phải được thay thế bằng mã xấu:

    queryForObject(sql, new Object { arg1, arg2, ...}, Integer.class);

hoặc cái này (đẹp hơn):

    queryForObject(sql, Integer.class, arg1, arg2, ...);

12
Điều đó không đúng. Đoạn mã thứ ba KHÔNG bằng với việc triển khai! Bởi vì có một NPE ẩn với tính năng tự động mở hộp. Nếu truy vấn của bạn trả về kết quả, nhưng chúng là null, mã trước đó sẽ trả về 0 thay vì null - để tái tạo đúng hành vi trước đó, nó sẽ là: Integer result = queryForObject (sql, args, Integer.class); trả về kết quả == null? 0: kết quả;
MetroidFan2002

@ MetroidFan2002: Quả thực nhận xét của bạn là đúng! Tuy nhiên, từ quan điểm của thiết kế API, nếu truy vấn chỉ trả về một giá trị NULL, tôi tin rằng tốt hơn nên trả về nguyên giá trị đó, thay vì tích lũy rằng (như queryForInt do) một NULL tương đương với 0. Đó là công việc của người dùng API để đánh giá loại điều kiện đó.
Gabriel Belingueres

Vấn đề là nếu và khi người dùng nhận được một NPE ở đó, trừ khi họ thiết lập rõ ràng một số thứ nhất định trong môi trường của họ (ví dụ: Eclipse có một tùy chọn để làm nổi bật việc sử dụng autoboxing), NPE trên dòng đó sẽ giống như phiên bản JDBCOperations là null. Trước đây, số 0 sẽ được trả về. Bây giờ tại sao bạn lại sử dụng điều này trong một truy vấn trả về null, tôi không biết (điều này về cơ bản là do n00bs thực hiện, điều này sẽ xảy ra), nhưng việc loại bỏ chúng không phải là một động thái tuyệt vời IMO.
MetroidFan2002

Tôi tìm thấy một lý do có thể là vì không chính xác. Tôi có một giá trị dài là 10000000233174211 được trả về bởi queryForLong (Chuỗi), nhưng thay vào đó nó đang trả về 10000000233174212. tức là +1. Tôi đã xem mã và nó chuyển đổi Double thành Long, vì vậy có lẽ có một số vấn đề với việc chuyển đổi.
mrswadge

Suy nghĩ thêm về nhận xét của tôi ở trên, kiểu dữ liệu cho cột là số (19,0), vì vậy có thể đây là lý do tại sao double lại có tác dụng? Tôi đã giải quyết được vấn đề bằng cách sử dụng queryForObject (sql, Long.class).
mrswadge

35

Tôi đồng ý với người đăng ban đầu rằng việc không dùng phương thức tiện lợi queryForLong (sql) là một điều bất tiện.

Tôi đã phát triển một ứng dụng bằng Spring 3.1 và vừa cập nhật lên phiên bản Spring mới nhất (3.2.3) và nhận thấy rằng nó không được dùng nữa.

May mắn thay, đó là một thay đổi dòng đối với tôi:

return jdbcTemplate.queryForLong(sql);  // deprecated in Spring 3.2.x

đã được đổi thành

return jdbcTemplate.queryForObject(sql, Long.class);

Và một số Bài kiểm tra đơn vị dường như cho thấy, thay đổi trên có hiệu quả.


điểm tốt. Nó sẽ hoạt động tốt nếu không có dấu ngoặc đơn. :)
SGB

14

Không được ủng hộ queryForObject(String, Class).


13

Thay thế mã như vậy:

long num = jdbcTemplate.queryForLong(sql);

Với mã này:

long num = jdbcTemplate.queryForObject(sql, Long.class);

rất nguy hiểm bởi vì nếu cột có giá trị null queryForObject trả về giá trị null và như chúng ta biết các kiểu nguyên thủy không thể là null và Bạn sẽ có NullPointerException. Trình biên dịch đã không cảnh báo Bạn về điều này. Bạn sẽ biết về lỗi này trong thời gian chạy. Bạn sẽ gặp lỗi tương tự nếu bạn có phương thức trả về kiểu nguyên thủy:

public long getValue(String sql) {
    return = jdbcTemplate.queryForObject(sql, Long.class);
}

Phương thức queryForLong không dùng nữa trong JdbcTemplate trong Spring 3.2.2 có nội dung sau:

@Deprecated
public long queryForLong(String sql) throws DataAccessException {
    Number number = queryForObject(sql, Long.class);
    return (number != null ? number.longValue() : 0);
}

Bạn thấy trước khi chúng trả về giá trị nguyên thủy, có kiểm tra rằng đây không phải là null và nếu nó là null, chúng sẽ trả về 0. Nhân tiện - Nên là 0L.


3
2 xu: Trình biên dịch có thể cảnh báo bạn về điều đó, nếu bạn bật cảnh báo tự động đóng hộp.
keiki

Tôi không biết về điều đó. Cảm ơn người bạn đời :)
Marcin Kapusta

2

JdbcTemplate#queryForInttrả về 0 nếu giá trị cột là SQL NULL hoặc 0. Không có cách nào để phân biệt trường hợp này với trường hợp kia. Tôi nghĩ đây là lý do chính tại sao phương pháp này không được dùng nữa. BTW, ResultSet#getInthoạt động tương tự. Mặc dù vậy, chúng ta có thể phân biệt giữa hai trường hợp này bằng cách ResultSet#wasNull.


-1
public int getCircleCount() {
    Object param = "1";
    String sql = "select count(*) from circle where id = ? ";
    jdbcTemplate.setDataSource(getDataSource());
    int result = getJdbcTemplate().queryForObject(sql, new Object[] { param }, Integer.class);
    return result;
}

Hãy giải thích câu trả lời của bạn.
Harsh Wardhan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.