?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
在Spring的JDBC框架的所有工作模式中貫徹了一些與參數(shù)和數(shù)據(jù)處理相關的基本原則。
多數(shù)情況下,Spring會根據(jù)傳入的參數(shù)值來設定相應的SQL類型。有時,我們有必要明確指定傳入?yún)?shù)所代表的SQL類型,這一點對于正確設置NULL值的時候可能比較有用。
另外還有一些其他的不同方面的作用:
多數(shù)JdbcTemplate
的update或者query方法會接收一個額外的int數(shù)組構成的參數(shù)。
這個數(shù)組需要提供的是使用java.sql.Types
中所定義的SQL類型。而這個數(shù)組中定義的類型需要與每個傳入的參數(shù)所對應。
你可以使用SqlParameterValue
對參數(shù)進行額外的封裝從而包裝更多的參數(shù)信息。通過傳入?yún)?shù)值和對應的SQL類型作為構造函數(shù)的參數(shù),你可以創(chuàng)建這個類的一個實例。
你也可以為numeric的值提供一些額外的精度要求。
對于那些使用命名參數(shù)的情況,你可以使用SqlParameterSource
、BeanPropertySqlParameterSource
或者MapSqlParameterSource
類。
他們都具備了為命名參數(shù)注冊SQL類型的功能。
你可以在數(shù)據(jù)庫中存儲圖像、二進制對象或者大文本等對象。這些較大的二進制對象被稱之為BLOB類型,而對應的大文本對象被稱之為CLOB對象。
Spring允許你使用JdbcTemplate、更高層次封裝的RDBMS對象和SimpleJdbc類對這些大對象進行操作。 所有的這些操作方式都實現(xiàn)了LobHandler
接口來處理LOB類型的數(shù)據(jù)。
LobHandler
接口提供了訪問LobCreator
的方法,通過調(diào)用getLobCreator
,你可以創(chuàng)建一個新的LOB類型的數(shù)據(jù)。
LobCreator/LobHandler
接口針對LOB類型的數(shù)據(jù)操作提供了下列支持:
BLOB
byte[] – getBlobAsBytes and setBlobAsBytes
byte[] – getBlobAsBytes 和 setBlobAsBytes
InputStream – getBlobAsBinaryStream and setBlobAsBinaryStream
InputStream – getBlobAsBinaryStream和setBlobAsBinaryStream
CLOB
String – getClobAsString and setClobAsString
String – getClobAsString和setClobAsString
InputStream – getClobAsAsciiStream and setClobAsAsciiStream
InputStream – getClobAsAsciiStream和setClobAsAsciiStream
Reader – getClobAsCharacterStream and setClobAsCharacterStream
Reader – getClobAsCharacterStream和setClobAsCharacterStream
現(xiàn)在我們通過一個示例來展示如何創(chuàng)建一個BLOB數(shù)據(jù)并插入數(shù)據(jù)庫。稍后的例子,我們將展示如何從數(shù)據(jù)庫中將BLOB數(shù)據(jù)讀取出來。
這個例子使用JdbcTemplate和一個AbstractLobCreatingPreparedStatementCallback的實現(xiàn)類。 這里唯一需要實現(xiàn)的方法就是"setValues"。在這個方法中,將提供一個LobCreator接口,被用作在你的插入語句中設置LOB字段的值。
我們假設有一個變量叫做“l(fā)obHandler”已經(jīng)被設置到DefaultLobHandler
的實例中。當然,這是由注入完成的。
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();
![]() |
我們在這里使用的lobHandler實現(xiàn)類是一個普通的 |
![]() |
使用 |
![]() |
使用 |
現(xiàn)在我們來示范從數(shù)據(jù)庫中讀取LOB數(shù)據(jù)。我們這里再次使用JdbcTempate并使用相同的DefaultLobHandler
實例。
List l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table", new RowMapper() { public Object mapRow(ResultSet rs, int i) throws SQLException { Map results = new HashMap(); String clobText = lobHandler.getClobAsString(rs, "a_clob"); results.put("CLOB", clobText); byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob"); results.put("BLOB", blobBytes); return results; } });
![]() |
使用 |
![]() |
使用 |
SQL標準允許基于一個帶參數(shù)列表的表達式進行查詢。一個典型的例子可能像這樣:"select * from T_ACTOR where id in (1, 2, 3)"。
不過這種參數(shù)列表的方式并不能直接被JDBC標準所支持 - 因為并不存在這種聲明一個列表參數(shù)作為占位符的方式。
你不得不為此寫多個占位符來表示多個參數(shù),或者當你知道占位符的數(shù)量時,你可以動態(tài)構建SQL字符串。
NamedParameterJdbcTemplate
和SimpleJdbcTemplate
中所提供的命名參數(shù)的特性,采用的是后面一種做法。
當你傳入?yún)?shù)時,你需要傳入一個java.util.List
類型,支持基本類型。而這個list將會在SQL執(zhí)行時替換占位符并傳入?yún)?shù)。
在使用IN語句時,當你傳入大批量的值時要小心,JDBC標準并不確保超過100個元素在IN語句中。 有不少數(shù)據(jù)庫可以超出這個值的限制,但是不同的數(shù)據(jù)庫會有不同的數(shù)量限制,比如Oracle的限制數(shù)量是1000個。
除了基本類型之外,你還可以創(chuàng)建一個java.util.List
的對象數(shù)組,這可以讓你支持在IN表達式中編寫多重表達式,例如"select * from T_ACTOR where (id, last_name) in ((1,
'Johnson'), (2, 'Harrop'))". 當然,這樣做的前提是數(shù)據(jù)庫底層的語法支持。
當調(diào)用存儲過程時,有時需要使用數(shù)據(jù)庫特定的復雜類型。為了適應這些類型,Spring提供了SqlReturnType
類來處理存儲過程的返回值,而使用SqlTypeValue
來處理傳入的參數(shù)。
下面這個例子,將Oracle的STRUCT對象作為返回值,這是一個由用戶自定義的“ITEM_TYPE”。
SqlReturnType
接口有唯一的方法“getTypeValue
”需要被實現(xiàn)。而這個接口的實現(xiàn)將被用作SqlOutParameter
聲明的一部分。
declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE", new SqlReturnType() { public Object getTypeValue(CallableStatement cs, int colIndx, int sqlType, String typeName) throws SQLException { 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; } }));
通過Java代碼調(diào)用存儲過程使用SqlTypeValue
來傳入一個TestItem
作為參數(shù)。
SqlTypeValue
接口有一個方法"createTypeValue
"需要被實現(xiàn)。
一個活動的數(shù)據(jù)庫連接也同時被傳入,它將被用作創(chuàng)建數(shù)據(jù)庫特定的對象,類似StructDescriptor
和ArrayDescriptor
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; } };
這里的SqlTypeValue
現(xiàn)在可以被加入到作為參數(shù)的Map中去,從而可以執(zhí)行相應的存儲過程。