JdbcTemplate queryForInt / Long tidak digunakan lagi di Spring 3.2.2. Apa yang harus diganti?

104

Metode queryforInt / queryforLong di JdbcTemplate tidak digunakan lagi di Spring 3.2. Saya tidak dapat mengetahui mengapa atau apa yang dianggap praktik terbaik untuk mengganti kode yang ada menggunakan metode ini.

Metode tipikal:

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

OK cara diatas perlu ditulis ulang sebagai berikut:

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

Jelas penghentian ini membuat kelas JdbcTemplate lebih sederhana (atau bukan?). QueryForInt selalu merupakan metode praktis (saya kira) dan sudah ada sejak lama. Mengapa telah dihapus. Akibatnya, kode menjadi lebih rumit.

Dan MacBean
sumber
Detail ini metode yang tidak digunakan lagi: static.springsource.org/spring/docs/current/javadoc-api/…
Dan MacBean
Anda benar, saya tidak tahu mengapa sumber saya tidak memiliki@Deprecated
Sotirios Delimanolis
Memperbarui versi Musim Semi ke 3.2.2 - sepertinya pertama kali tidak digunakan lagi di sini
Dan MacBean
Saya meningkatkan basis kode yang ada dari 3.1 menjadi 3.2.2 dan metode ini digunakan di semua tempat. Perlu memahami mengapa dan bagaimana memperbarui kode.
Dan MacBean
Ketahuilah bahwa queryForObject dapat kembali null(bukan kasus dalam contoh Anda). Saya tidak menemukan cara lain selain menduplikasi sekarang kode cek nol dari queryForInt / Long.
hochraldo

Jawaban:

110

Apa yang saya pikirkan adalah seseorang menyadari bahwa metode queryForInt / Long memiliki semantik yang membingungkan, yaitu, dari kode sumber JdbcTemplate Anda dapat melihat implementasinya saat ini:

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

yang mungkin membuat Anda berpikir bahwa jika set hasil kosong, ia akan mengembalikan 0, namun ia mengeluarkan pengecualian:

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

jadi implementasi berikut pada dasarnya sama dengan yang sekarang:

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

Dan kemudian kode yang tidak digunakan lagi sekarang harus diganti dengan yang jelek:

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

atau ini (lebih bagus):

    queryForObject(sql, Integer.class, arg1, arg2, ...);
Gabriel Belingueres
sumber
12
Itu tidak benar. Potongan kode ketiga TIDAK sama dengan implementasi! Karena ada NPE tersembunyi dengan unboxing otomatis. Jika kueri Anda memberikan hasil, tetapi hasilnya nol, kode sebelumnya akan mengembalikan 0, bukan null - untuk mereproduksi perilaku sebelumnya dengan benar, ini akan menjadi: Integer result = queryForObject (sql, args, Integer.class); mengembalikan hasil == null? 0: hasil;
MetroidFan2002
@ MetroidFan2002: Memang pengamatan Anda benar! Namun, dari sudut pandang desain API, jika kueri hanya mengembalikan satu nilai NULL, saya yakin lebih baik mengembalikannya sebagaimana adanya, daripada mengasumsikan bahwa (seperti yang dilakukan queryForInt) sebuah NULL setara dengan 0. Itu adalah pekerjaan pengguna API untuk mengevaluasi kondisi semacam itu.
Gabriel Belingueres
Masalahnya adalah jika dan ketika pengguna mendapatkan NPE di sana, kecuali mereka secara eksplisit mengatur hal-hal tertentu di lingkungan mereka (misalnya, Eclipse memiliki opsi untuk menyorot penggunaan autoboxing), NPE pada baris itu akan terlihat seperti contoh JDBCOperations adalah nol. Sebelumnya, nol akan dikembalikan. Sekarang mengapa Anda akan menggunakan ini dalam kueri yang mengembalikan nol, saya tidak tahu (ini pada dasarnya karena n00bs melakukannya, yang akan mereka lakukan), tetapi mengambil ini bukanlah langkah yang bagus IMO.
MetroidFan2002
Saya menemukan kemungkinan alasannya adalah karena ketidaktepatan. Saya memiliki nilai panjang 10000000233174211 dikembalikan oleh queryForLong (String), tetapi malah mengembalikan 10000000233174212. yaitu +1. Saya melihat kode dan mengubah Double menjadi Long, jadi mungkin ada beberapa masalah dengan konversi.
mrswadge
Memikirkan komentar saya di atas sedikit lebih jauh, tipe data untuk kolomnya adalah angka (19,0), jadi mungkin inilah mengapa double ikut bermain? Saya mengatasi masalah ini dengan menggunakan queryForObject (sql, Long.class).
mrswadge
35

Saya setuju dengan poster asli bahwa mencabut metode kenyamanan queryForLong (sql) adalah ketidaknyamanan.

Saya telah mengembangkan aplikasi menggunakan Spring 3.1 dan baru saja memperbarui ke versi Spring terbaru (3.2.3) dan menyadari bahwa aplikasi tersebut sudah usang.

Untungnya, itu adalah perubahan satu baris untuk saya:

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

diubah menjadi

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

Dan beberapa Tes Unit tampaknya menunjukkan, perubahan di atas berhasil.

SGB
sumber
poin yang bagus. Ini juga akan berfungsi dengan baik tanpa tanda kurung. :)
SGB
14

Tidak berlaku lagi mendukung queryForObject(String, Class).

vertti
sumber
13

Mengganti kode tersebut:

long num = jdbcTemplate.queryForLong(sql);

Dengan kode ini:

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

sangat berbahaya karena jika kolom memiliki nilai null queryForObject mengembalikan null dan seperti yang kita ketahui tipe primitif tidak bisa null dan Anda akan memiliki NullPointerException. Kompilator tidak memperingatkan Anda tentang hal ini. Anda akan tahu tentang kesalahan ini saat runtime. Kesalahan yang sama akan Anda alami jika Anda memiliki metode yang mengembalikan tipe primitif:

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

Metode queryForLong yang tidak digunakan lagi di JdbcTemplate pada Spring 3.2.2 memiliki isi berikut:

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

Anda lihat sebelum mereka mengembalikan nilai primitif ada pemeriksaan bahwa ini bukan null dan jika null mereka mengembalikan 0. By the way - Harus 0L.

Marcin Kapusta
sumber
3
2 sen: Kompilator mungkin memperingatkan Anda tentang hal itu, jika Anda mengaktifkan peringatan autoboxing.
keiki
Saya tidak tahu tentang itu. Terima kasih sobat :)
Marcin Kapusta
2

JdbcTemplate#queryForIntmengembalikan 0 jika nilai kolom adalah SQL NULL atau 0. Tidak ada cara untuk membedakan satu kasus dari yang lain. Saya rasa ini adalah alasan utama mengapa metode ini tidak digunakan lagi. BTW, ResultSet#getIntberperilaku serupa. Padahal, kita dapat membedakan kedua kasus ini dengan ResultSet#wasNull.

jddxf
sumber
-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;
}
Manikannan Arumugam
sumber
Tolong jelaskan jawaban Anda.
Harsh Wardhan