Ko'pgina JDBC drayverlari bir xil kompilyatsiyalangan statementga bir necha marta murojaat qilishda samaradorlikni oshirish imkonini beradi. Yangilanishlarni paketlarga guruhlab, siz ma'lumotlar bazasiga aylanma murojaat qilishlar sonini cheklaysiz.
JdbcTemplate yordamida asosiy paket operatsiyalari
JdbcTemplateda paketli ishlov berishni amalga oshirasiz, maxsus interfeys BatchPreparedStatementSetterning ikkita metodini amalga oshirib, ushbu amalga oshiruvni batchUpdate metodiga ikkinchi parametr sifatida uzatasiz. getBatchSize metodi kompilyatsiyalangan statement parametrlarini o'rnatish uchun ishlatilishi mumkin. setValues metodi tayyorlangan instruktsiya parametrlarini o'rnatish uchun ishlatilishi mumkin. Ushbu metod getBatchSize chaqiriladigan miqdorda chaqiriladi. Keyingi misolda t_actor jadvali ro'yxatdagi yozuvlar asosida yangilanadi va butun ro'yxat paket sifatida ishlatiladi:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[] batchUpdate(final List<Actor> actors) {
return this.jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
Actor actor = actors.get(i);
ps.setString(1, actor.getFirstName());
ps.setString(2, actor.getLastName());
ps.setLong(3, actor.getId().longValue());
}
public int getBatchSize() {
return actors.size();
}
});
}
// ... qo'shimcha metodlar
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
object: BatchPreparedStatementSetter {
override fun setValues(ps: PreparedStatement, i: Int) {
ps.setString(1, actors[i].firstName)
ps.setString(2, actors[i].lastName)
ps.setLong(3, actors[i].id)
}
override fun getBatchSize() = actors.size
})
}
// ... qo'shimcha metodlar
}
Agar siz yangilanayotgan oqim yoki fayldan o'qiyapgan bo'lsangiz, sizda allaqachon taklif qilingan paket hajmi bo'lishi mumkin, lekin oxirgi paketda shunday yozuvlar soni bo'lmasligi mumkin. Bunday holatda, InterruptibleBatchPreparedStatementSetter interfeysidan foydalanishingiz mumkin, bu sizga kirish ma'lumotlari manbai tugagandan so'ng paketi to'xtatishga imkon beradi. isBatchExhausted metodi paket tugashini signal qilish imkonini beradi.
Obyektlar ro'yxatini ishlatib paket operatsiyalari
JdbcTemplate va NamedParameterJdbcTemplate paket yangilanishini ta'minlashning muqobil usulini taqdim etadi. Maxsus paket interfeysini amalga oshirish o'rniga, siz barcha parametr qiymatlarini chaqirishda ro'yxat sifatida taqdim etasiz. Framework bu qiymatlarni takrorlaydi va ichki kompilyatsiyalangan statement setterdan foydalanadi. API interfeysi siz foydalanayotgan parametrlar nomlangan yoki yo'qligiga qarab farq qiladi. Nomlangan parametrlar uchun siz har bir guruh a'zosi uchun bitta yozuv bilan SqlParameterSource massivini belgilaysiz. Bu massivni yaratish uchun SqlParameterSourceUtils.createBatch yordamchi metodlaridan foydalanishingiz mumkin, bu parametrlar mos keladigan getterlardan foydalangan holda bean asosidagi obyektlar massivini, String kaliti bilan Map misollarini (mos keladigan parametrlarni qiymat sifatida o'z ichiga olgan) yoki ikkalasining kombinatsiyasini uzatadi.
Quyidagi misolda nomlangan parametrlar yordamida paket yangilanishi ko'rsatilgan:
public class JdbcActorDao implements ActorDao {
private NamedParameterTemplate namedParameterJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public int[] batchUpdate(List<Actor> actors) {
return this.namedParameterJdbcTemplate.batchUpdate(
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
SqlParameterSourceUtils.createBatch(actors));
}
// ... qo'shimcha metodlar
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
return this.namedParameterJdbcTemplate.batchUpdate(
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
SqlParameterSourceUtils.createBatch(actors));
}
// ... qo'shimcha metodlar
}
SQL-statement uchun, klassik ? o'rin egalarini ishlatgan holda, siz yangilanish qiymatlari bilan obyekt massivini o'z ichiga olgan ro'yxatni uzatasiz. Ushbu obyektlar massivi SQL-dagi har bir o'rin egasi uchun bitta elementga ega bo'lishi kerak va ular SQL-statementsida aniqlangan tartibda joylashtirilishi kerak.
Keyingi misol avvalgisiga o'xshaydi, faqat unda JDBC uchun klassik ? o'rin egalaridan foydalaniladi:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[] batchUpdate(final List<Actor> actors) {
List<Object[]> batch = new ArrayList<Object[]>();
for (Actor actor : actors) {
Object[] values = new Object[] {
actor.getFirstName(), actor.getLastName(), actor.getId()};
batch.add(values);
}
return this.jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
batch);
}
// ... qo'shimcha metodlar
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): IntArray {
val batch = mutableListOf<Array<Any>>()
for (actor in actors) {
batch.add(arrayOf(actor.firstName, actor.lastName, actor.id))
}
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?", batch)
}
// ... qo'shimcha metodlar
}
Yuqorida tavsiflangan barcha paketli yangilanish metodlari har bir paket yozuvi uchun ta'sirlangan qatorlar sonini o'z ichiga olgan int massivini qaytaradi. Bu hisoblagich JDBC drayveri tomonidan xabar beriladi. Agar hisoblagich mavjud bo'lmasa, JDBC drayveri -2 qiymatini qaytaradi.
Bunday ssenariyda, asosiy PreparedStatement da qiymatlarni avtomatik o'rnatishda, har bir qiymat uchun mos keladigan JDBC turi ushbu Java turidan hosil bo'lishi kerak. Garchi bu odatda yaxshi ishlaydi, lekin muammolar paydo bo'lishi mumkin (masalan, Map ichida mavjud bo'lgan null qiymatlari). Bunday holda, Spring odatda ParameterMetaData.getParameterType ni chaqiradi, bu sizning JDBC drayveringizni ishlatishda qimmatga tushishi mumkin. Eng so'nggi drayver versiyasidan foydalanish va agar siz ishlash muammosiga duch kelsangiz (Oracle 12c, JBoss va PostgreSQLda xabar qilinganidek), spring.jdbc.getParameterType.ignore xususiyatini true ga o'rnatishni ko'rib chiqish kerak (JVM tizim xususiyati sifatida yoki SpringProperties mexanizmi orqali).
Bundan tashqari, tegishli JDBC turlarini BatchPreparedStatementSetter (oldin ko'rsatilganidek) orqali yoki List<Object[]> asosida chaqirilganda uzatiladigan aniq massivlar orqali yoki foydalanuvchi misoli uchun registerSqlType chaqiruvi orqali aniq belgilashni ko'rib chiqish mumkin MapSqlParameterSource, yoki BeanPropertySqlParameterSource, u hatto bo'sh qiymat uchun ham Java turidagi xususiyatdan SQL turini chiqarib beradi.
Bir necha paketlar yordamida paket operatsiyalari
Oldingi paket yangilanishi misolida, paketlar shu qadar kattaki, ularni bir nechta kichik paketlarga ajratishga to'g'ri keladi. Buni ilgari keltirilgan metodlar yordamida amalga oshirish mumkin, batchUpdate metodini bir necha marta chaqirish orqali, lekin endi engillik beruvchi metod ham mavjud. Ushbu metod SQL-instruktsiyasidan tashqari, kompyuterdagi har bir paket uchun yangilanishlar sonini va kompilyatsiyalangan stament parametrlarini o'rnatish uchun ParameterizedPreparedStatementSetter qabul qiladi. Framework taqdim etilgan qiymatlarni takrorlaydi va yangilash chaqiruvlarini belgilangan hajmdagi paketlarga ajratadi.
Keyingi misolda 100 o'lchamli paketdan foydalangan holda paket yangilanishi ko'rsatilgan:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[][] batchUpdate(final Collection<Actor> actors) {
int[][] updateCounts = jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
actors,
100,
(PreparedStatement ps, Actor actor) -> {
ps.setString(1, actor.getFirstName());
ps.setString(2, actor.getLastName());
ps.setLong(3, actor.getId().longValue());
});
return updateCounts;
}
// ... qo'shimча metodlar
}
class JdbcActorDao(dataSource: DataSource) : ActorDao {
private val jdbcTemplate = JdbcTemplate(dataSource)
fun batchUpdate(actors: List<Actor>): Array<IntArray> {
return jdbcTemplate.batchUpdate(
"update t_actor set first_name = ?, last_name = ? where id = ?",
actors, 100) { ps, argument ->
ps.setString(1, argument.firstName)
ps.setString(2, argument.lastName)
ps.setLong(3, argument.id)
}
}
// ... qo'shimcha metodlar
}
Bu chaqiruvning paket yangilanishi metodi int massivlari massivini qaytaradi, u har bir paket uchun qaydlar massivi va har bir yangilanish uchun ta'sirlangan qatorlar soni massivi bilan ta'minlaydi. Yuqori darajadagi massiv uzunligi ishlatilgan paketlar sonini ko'rsatadi, ikkinchi darajadagi massiv uzunligi esa ushbu paketdagi yangilanishlar miqdorini ko'rsatadi. Har bir paketdagi yangilanishlar miqdori belgilangan paket hajmiga tegishli bo'lishi kerak (oxirgi paketdan boshqa, ular umumiy yangilanishi kiritilgan obyektlar soniga bog'liq bo'lib, kichikroq bo'lishi mumkin). Har bir yangilanish instruktsiyasining yangilanishi hisoblagichi JDBC drayveri tomonidan xabar qilinadi. Agar hisoblagich mavjud bo'lmasa, JDBC drayveri -2 qiymatini qaytaradi.
GO TO FULL VERSION