SQL turlari haqida ma'lumotlarni parametrlar uchun ko'rsatish
Odatda, Spring parametrlarning SQL turini uzatilgan parametrning turiga qarab aniqlaydi. Parametrlar qiymatlarini sozlashda foydalaniladigan SQL turini aniq belgilashingiz mumkin. Ba'zida NULL qiymatlarini to'g'ri o'rnatish uchun bu zarur.
SQL turi haqida ma'lumotni bir necha usulda ko'rsatish mumkin:
-
JdbcTemplateshabloni bilan yangilash va sorov usullarining ko'pchiligiintmassiv shaklida qo'shimcha parametrni qabul qiladi. Bu massivjava.sql.Typessinfidagi doimiy qiymatlardan foydalanib, tegishli parametrning SQL turini ko'rsatish uchun ishlatiladi. Har bir parametr uchun bitta yozuv kiriting. -
SqlParameterValuesinfini qo'shimcha ma'lumot talab qiladigan parametr qiymatini o'rash uchun foydalanishingiz mumkin. Buning uchun har bir qiymat uchun yangi nusxasini yarating va konstruktorida SQL turi va parametr qiymatini kiriting. Shuningdek, raqamli qiymatlar uchun ixtiyoriy masshtab parametrini ko'rsatishingiz mumkin. -
Nomli parametrlar bilan ishlaydigan usullar uchun
SqlParameterSource,BeanPropertySqlParameterSourceyokiMapSqlParameterSourcesinflaridan foydalanishingiz mumkin. Ular nomli parametrlarning har qanday qiymati uchun SQL turini ro'yxatdan o'tkazish uchun usullarga ega.
BLOB va CLOB ob'ektlarini ishlash
Ma'lumotlar bazasida rasmlar, boshqa ikkilik ma'lumotlar va katta hajmdagi matnli parchalar saqlanishi mumkin. Ikki turdagi ma'lumotlar holatida, bu katta ob'ektlar ikkiyuluk katta ob'ektlar deb ataladi, yoki qisqasi BLOB (Binary Large Object), va belgili katta ob'ektlar, yoki qisqasi CLOB (Character Large Object), belgili ma'lumotlar holatida. Spring'da bunday katta ob'ektlar bilan JdbcTemplate'ni to'g'ridan-to'g'ri foydalanib, shuningdek, RDBMS va SimpleJdbc sinflari orqali yuqori darajadagi abstraksiyalarni foydalanib ishlash mumkin. Ushbu usullarning barchasi LOB (Large Object) ma'lumotlarini haqiqiy boshqarish uchun LobHandler interfeys implementatsiyasidan foydalanadi. LobHandler LOB ob'ektlarini qo'shish uchun getLobCreator usuli orqali LobCreator klassiga kirishni taqdim etadi.
LobCreator va LobHandler LOB'ning quyidagi kirish va chiqishini ta'minlaydi:
-
BLOB
-
byte[]:getBlobAsBytesvasetBlobAsBytes -
InputStream:getBlobAsBinaryStreamvasetBlobAsBinaryStream
-
-
CLOB
-
String:getClobAsStringvasetClobAsString -
InputStream:getClobAsAsciiStreamvasetClobAsAsciiStream -
Reader:getClobAsCharacterStreamvasetClobAsCharacterStream
-
Quyidagi misolda BLOB yaratish va kiritish ko'rsatilgan. Keyinchalik uni ma'lumotlar bazasidan qaytarib o'qish qanday amalga oshirilishi namoyish etiladi.
Ushbu misolda JdbcTemplate va AbstractLobCreatingPreparedStatementCallback'ni ishlatish ko'rsatilgan. U bitta usulni amalga oshiradi, setValues. Ushbu usul LOB ustunlar qiymatlarini SQL bayonot kiritish ichida o'rnatish uchun foydalaniladigan LobCreator'ni taqdim etadi.
Ushbu misolda, lobHandler o'zgaruvchisi mavjud deb faraz qilinmoqda, u DefaultLobHandler instantsi uchun o'rnatilgan. Odatda bu qiymat dependency injection orqali o'rnatiladi.
Quyidagi misolda BLOB yaratish va kiritish ko'rsatilgan:
final File blobIn = new File("spring2004.jpg");
final InputStream blobIs = new FileInputStream(blobIn);
final File clobIn = new File("large.txt");
final InputStream clobIs = new FileInputStream(clobIn);
final InputStreamReader clobReader = new InputStreamReader(clobIs);
jdbcTemplate.execute(
"INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)",
new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {
ps.setLong(1, 1L);
lobCreator.setClobAsCharacterStream(ps, 2, clobReader, (int)clobIn.length());
lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, (int)blobIn.length());
}
}
);
blobIs.close();
clobReader.close();
lobHandlerni uzatamiz, u (ushbu misolda) oddiyDefaultLobHandler.- CLOB mazmunini uzatish uchun
setClobAsCharacterStreamusulidan foydalanish. - BLOB mazmunini uzatish uchun
setBlobAsBinaryStreamusulidan foydalanish.
val blobIn = File("spring2004.jpg")
val blobIs = FileInputStream(blobIn)
val clobIn = File("large.txt")
val clobIs = FileInputStream(clobIn)
val clobReader = InputStreamReader(clobIs)
jdbcTemplate.execute(
"INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)",
object: AbstractLobCreatingPreparedStatementCallback(lobHandler) {
override fun setValues(ps: PreparedStatement, lobCreator: LobCreator) {
ps.setLong(1, 1L)
lobCreator.setClobAsCharacterStream(ps, 2, clobReader, clobIn.length().toInt())
lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, blobIn.length().toInt())
}
}
)
blobIs.close()
clobReader.close()
lobHandlerni uzatamiz, u (ushbu misolda) oddiyDefaultLobHandler.- CLOB mazmunini uzatish uchun
setClobAsCharacterStreamusulidan foydalanish. - BLOB mazmunini uzatish uchun
setBlobAsBinaryStreamusulidan foydalanish.
Agar DefaultLobHandler.getLobCreator()dan qaytgan LobCreator uchun setBlobAsBinaryStream, setClobAsAsciiStream yoki setClobAsCharacterStream usulini chaqirsangiz, contentLength argumenti uchun ixtiyoriy manfiy qiymat belgilashingiz mumkin. Agar ko'rsatilgan mazmun uzunligi manfiy bo'lsa, DefaultLobHandler mazmun uzunligi parametrisiz JDBC 4.0 usullarining variantlarini ishlatadi. Aks holda, u ko'rsatilgan uzunlikni drayverga uzatadi.
QIymatlarni oqim qilishni qo'llab-quvvatlash uchun foydalanayotgan JDBC drayveringiz hujjatiga qarang, chunki ba'zi drayverlar mazmun uzunligini ko'rsatmasdan LOB oqimini qo'llab-quvvatlamaydi.
Endi ma'lumotlar bazasidan LOB ma'lumotlarni o'qish vaqti keldi. Yana bir bor JdbcTemplate ishlatilmoqda va lobHandler va DefaultLobHandler'ga qayta ulanmoqda. Quyidagi misolda bu qanday amalga oshirilishi ko'rsatilgan:
List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",
new RowMapper<Map<String, Object>>() {
public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException {
Map<String, Object> results = new HashMap<String, Object>();
String clobText = lobHandler.getClobAsString(rs, "a_clob");
results.put("CLOB", clobText);
byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob");
results.put("BLOB", blobBytes);
return results;
}
});
- CLOB mazmunini olish uchun
getClobAsStringusulidan foydalanish. - BLOB mazmunini olish uchun
getBlobAsBytesusulidan foydalanish.
val l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table") { rs, _ ->
val clobText = lobHandler.getClobAsString(rs, "a_clob")
val blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob")
mapOf("CLOB" to clobText, "BLOB" to blobBytes)
}
- CLOB mazmunini olish uchun
getClobAsStringusulidan foydalanish. - BLOB mazmunini olish uchun
getBlobAsBytesusulidan foydalanish.
"IN" ifodasi uchun qiymatlar ro'yxatini o'tkazish
SQL standarti o'zgaruvchi qiymatlar ro'yxatini o'z ichiga olgan ifoda asosida qatorlarni tanlashga imkon beradi. Misol uchun, select * from T_ACTOR where id in (1, 2, 3). Ushbu o'zgaruvchi ro'yxati tayyorlangan bayonotlar uchun JDBC standarti tomonidan to'g'ridan-to'g'ri qo'llab-quvvatlanmaydi. O'zgaruvchilar sonini ko'rsatadigan joy ushlagichlarni tayyorlash kerak bo'ladi. Yoki kerakli ushlagichlar soni ma'lum bo'lganda, dinamik SQL satrini yaratish kerak. NamedParameterJdbcTemplate va JdbcTemplateda taqdim etilgan nomli parametrlarni qo'llab-quvvatlash vositalari oxirgi yondashuvni qo'llaydi. Siz qiymatlarni java.util.List primitivi ob'ektlari ro'yxati sifatida topshirishingiz mumkin. Bu ro'yxatdan kerakli ushlagichlar qo'shiladi va bajarilish vaqtida qiymatlar uzatiladi.
in ifodalar ro'yxati uchun qiymatlarni qo'llab-quvvatlashni kafolatlamaydi. Turli ma'lumotlar bazalari ushbu raqamni oshib o'tishga imkon beradi, lekin odatda ular ruxsat berilgan qiymatlar soniga cheklangan chegaraga ega. Masalan, Oracle'ning limiti 1000.
Shuningdek, qiymatlar ro'yxatidagi primitv qiymatlardan tashqari, ob'ektlarning massivlari ro'yxatini ham yaratishingiz mumkin. Bu ro'yxat in ifoda uchun aniqlangan bir nechta ifodalarni qo'llab-quvvatlashi mumkin, masalan, select * from T_ACTOR where (id, last_name) in ((1, 'Johnson'), (2, 'Harrop')). Buning uchun, albatta, ma'lumotlar bazangiz ushbu sintaksisni qo'llab-quvvatlashi kerak.
Saqlangan protseduralar chaqiruvlari uchun murakkab turlarni ishlash
Saqlangan protseduralarni chaqirishda ba'zan ma'lumotlar bazasi uchun o'ziga xos murakkab turlarni ishlatishingiz mumkin. Ushbu turlar bilan ishlash uchun Spring ulardan foydalanadi: saqlangan protsedura chaqiruvining natijasi sifatida qaytariladigan murakkab turlarini ishlash uchun SqlReturnType va agar ular saqlangan protseduraning parametri sifatida uzatilayotgan bo'lsa, SqlTypeValue.
SqlReturnType interfeysi bitta usulga ega (uning nomi getTypeValue), uni amalga oshirish kerak bo'ladi. Ushbu interfeys SqlOutParameter parametrini e'lon qilishning bir qismi sifatida ishlatiladi. Quyidagi misolda foydalanuvchi tomonidan e'lon qilingan ITEM_TYPE tipidagi Oracle ob'ekti sifatida STRUCT qiymatini qaytarish ko'rsatilgan:
public class TestItemStoredProcedure extends StoredProcedure {
public TestItemStoredProcedure(DataSource dataSource) {
// ...
declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE",
(CallableStatement cs, int colIndx, int sqlType, String typeName) -> {
STRUCT struct = (STRUCT) cs.getObject(colIndx);
Object[] attr = struct.getAttributes();
TestItem item = new TestItem();
item.setId(((Number) attr[0]).longValue());
item.setDescription((String) attr[1]);
item.setExpirationDate((java.util.Date) attr[2]);
return item;
}));
// ...
}
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
init {
// ...
declareParameter(SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE") { cs, colIndx, sqlType, typeName ->
val struct = cs.getObject(colIndx) as STRUCT
val attr = struct.getAttributes()
TestItem((attr[0] as Long, attr[1] as String, attr[2] as Date)
})
// ...
}
}
Java ob'ektining qiymatini (masalan, TestItem) saqlangan protseduraga uzatish uchun SqlTypeValuedan foydalanishingiz mumkin. SqlTypeValue interfeysi bitta usulga ega (uning nomi createTypeValue), uni amalga oshirish kerak bo'ladi. Aktif aloqani uzatiladi va siz StructDescriptor yoki ArrayDescriptor nusxalari kabi ma'lumotlar bazasi uchun maxsus ob'ektlarni yaratish uchun foydalanishingiz mumkin. Quyidagi misolda StructDescriptor nusxasi yaratiladi:
final TestItem testItem = new TestItem(123L, "A test item",
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn);
Struct item = new STRUCT(itemDescriptor, conn,
new Object[] {
testItem.getId(),
testItem.getDescription(),
new java.sql.Date(testItem.getExpirationDate().getTime())
});
return item;
}
};
val (id, description, expirationDate) = TestItem(123L, "A test item",
SimpleDateFormat("yyyy-M-d").parse("2010-12-31"))
val value = object : AbstractSqlTypeValue() {
override fun createTypeValue(conn: Connection, sqlType: Int, typeName: String?): Any {
val itemDescriptor = StructDescriptor(typeName, conn)
return STRUCT(itemDescriptor, conn,
arrayOf(id, description, java.sql.Date(expirationDate.time)))
}
}
Endi ushbu SqlTypeValue qiymatini saqlangan protseduraning execute chaqiruvining kirish parametrlarini o'z ichiga olgan Mapga qo'shishingiz mumkin.
SqlTypeValueni yana bir qo'llanilishi bu Oracle'dagi saqlangan protseduraga qiymatlar massivini uzatishdir. Oracle bunday holatlarda foydalanilishi kerak bo'lgan o'zining ichki ARRAY sinfiga ega va siz SqlTypeValueni Oracle'dan ARRAY nusxasini yaratish va ARRAYdagi qiymatlar bilan to'ldirish uchun ishlatishingiz mumkin, quyidagi misolda ko'rsatilganidek:
final Long[] ids = new Long[] {1L, 2L};
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
return idArray;
}
};
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
init {
val ids = arrayOf(1L, 2L)
val value = object : AbstractSqlTypeValue() {
override fun createTypeValue(conn: Connection, sqlType: Int, typeName: String?): Any {
val arrayDescriptor = ArrayDescriptor(typeName, conn)
return ARRAY(arrayDescriptor, conn, ids)
}
}
}
}
GO TO FULL VERSION