使用spring 的 JdbcTemplate 進行sql 的操作, 對於每一次的如:query, update, batchUpdate,execute 這些方法, 執行一次都是調用不同的 Connection的.
所以如果你是對 oracle 的暫存資料表進行資料操作, 你update一次後, 在query 是讀取不到暫存資料表的資料的, 因為這兩次的操作對應的Connection是不同的.
為了能使用oracle 的暫存資料表, 就需要對每個操作提供一個相同 Connection, 以後的所有操作都跟這個 Connection產生的 Statement, PreparedStatement, CallableStatement 相關, 並且通過這些對象的getConnection() 方法也可以很容易就取得原來的 connection 對象.
由於以前沒用過Spring 的 JdbcTemplate, 所以邊工作的時候邊查詢 JdbcTemplate 的原始碼, 寫寫一些小功能測試.
其實JdbcTemplate 裡面很多方法的返回的結果都是用到了 execute() 這個方法的, 所以要擷取同一個 Connection 對象, 就要從 execute() 入手.
1. execute(ConnectionCallback action)
在JdbcTempate 的execute() 方法裡面,
//-------------------------------------------------------------------------<br />// Methods dealing with a plain java.sql.Connection<br />//-------------------------------------------------------------------------</p><p>public Object execute(ConnectionCallback action) throws DataAccessException;
在這個方法裡面介面 ConnectionCallback 定義如下
public interface ConnectionCallback {<br />Object doInConnection(Connection con) throws SQLException, DataAccessException;<br />}
在介面 ConnectionCallback 中聲明的方法Object doInConnection(Connection con) 中提供了參數 Connection conn, 這個剛好就是我們所需要的. 我們在實現 doInConnection(Connection con) 方法的過程中, 就可以自由使用 Connection conn.
2. 實現 ConnectionCallback 的方法有兩種
第一種: 直接定義介面
public Object mainOfImportExcel(fianl JdbcTemplate jdbcTemplate, final Object attachment) throws Exception{</p><p> return jdbcTemplate.execute(new ConnectionCallback(){<br /> public Object doInConnection(Connection con) throws SQLException {<br /> //TODO your code<br /> //return something<br />});<br />}
第二種: 寫一個ConnectionCallback介面的實作類別
Class ConnectionCallbackImpl implements ConnectionCallback{<br /> public Object doInConnection(Connection con) throws SQLException {<br /> //TODO your code<br /> //return something<br /> }<br /> private Object attachment;<br /> public Object getAttachment(){<br /> return this.attachment;<br /> }<br /> public void setAttachment(Object attachment){<br /> this.attachment = attachment;<br /> }<br />}
調用這個實作類別, new 也可以, 用注入的也可以
public Object mainOfImportExcel(fianl JdbcTemplate jdbcTemplate, final Object attachment) throws Exception{</p><p> return jdbcTemplate.execute(new ConnectionCallbackImpl());<br />}
3. 不足和補充
採用 ConnectionCall 介面的實現 oracle 暫存資料表的使用, 但這是要付出代價的. 那就是不能使用 JdbcTemplate 的方法了如查詢, 插入, 批量插入來處理暫存資料表的資料, 要等到暫存資料表的資料匯入到正式表後, 你才能對正式表使用 JdbcTemplate的查詢等方法, 對暫存資料表就沒有意義了.
但這不是致命的, 因為你可以自己實現這些方法, 參考下 JdbcTemplate 的原始碼, 你也可以寫出自己需要的方法.
下面是一個批量插入的方法, 就是借鑒了 JdbcTemplate 的batchUpdate 方法
public int[] doneBatchInsert(PreparedStatement pstmt, String sql, final List paramaterList) throws SQLException { </p><p> int batchSize =0;<br /> if(paramaterList != null) batchSize = paramaterList.size();<br /> //學 JdbcTemplate 的public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss)<br /> if (JdbcUtils.supportsBatchUpdates(pstmt.getConnection())) {<br /> for (int i = 0; i < batchSize; i++) {<br /> List list = (List) paramaterList.get(i);<br /> int j = 1;<br /> for (Iterator iterator = list.iterator(); iterator.hasNext(); j++) {<br /> pstmt.setString(j,<br /> (String) iterator.next());<br /> }<br /> pstmt.addBatch();<br /> }<br /> return pstmt.executeBatch();<br /> }<br /> else {<br /> List rowsAffected = new ArrayList();<br /> for (int i = 0; i < batchSize; i++) {<br /> List list = (List) paramaterList.get(i);<br /> int j = 1;<br /> for (Iterator iterator = list.iterator(); iterator.hasNext(); j++) {<br /> pstmt.setString(j,<br /> (String) iterator.next());<br /> }<br /> rowsAffected.add(new Integer(pstmt.executeUpdate()));<br /> }<br /> int[] rowsAffectedArray = new int[rowsAffected.size()];<br /> for (int i = 0; i < rowsAffectedArray.length; i++) {<br /> rowsAffectedArray[i] = ((Integer) rowsAffected.get(i)).intValue();<br /> }<br /> return rowsAffectedArray;<br /> }</p><p> }