使用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() 方法里面,
//------------------------------------------------------------------------- // Methods dealing with a plain java.sql.Connection //------------------------------------------------------------------------- public Object execute(ConnectionCallback action) throws DataAccessException;
在这个方法里面接口 ConnectionCallback 定义如下
public interface ConnectionCallback { Object doInConnection(Connection con) throws SQLException, DataAccessException; }
在接口 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{ return jdbcTemplate.execute(new ConnectionCallback(){ public Object doInConnection(Connection con) throws SQLException { //TODO your code //return something }); }
第二种: 写一个ConnectionCallback接口的实现类
Class ConnectionCallbackImpl implements ConnectionCallback{ public Object doInConnection(Connection con) throws SQLException { //TODO your code //return something } private Object attachment; public Object getAttachment(){ return this.attachment; } public void setAttachment(Object attachment){ this.attachment = attachment; } }
调用这个实现类, new 也可以, 用注入的也可以
public Object mainOfImportExcel(fianl JdbcTemplate jdbcTemplate, final Object attachment) throws Exception{ return jdbcTemplate.execute(new ConnectionCallbackImpl()); }
3. 不足和补充
采用 ConnectionCall 接口的实现 oracle 临时表的使用, 但这是要付出代价的. 那就是不能使用 JdbcTemplate 的方法了如查询, 插入, 批量插入来处理临时表的数据, 要等到临时表的数据导入到正式表后, 你才能对正式表使用 JdbcTemplate的查询等方法, 对临时表就没有意义了.
但这不是致命的, 因为你可以自己实现这些方法, 参考下 JdbcTemplate 的源代码, 你也可以写出自己需要的方法.
下面是一个批量插入的方法, 就是借鉴了 JdbcTemplate 的batchUpdate 方法
public int[] doneBatchInsert(PreparedStatement pstmt, String sql, final List paramaterList) throws SQLException { int batchSize =0; if(paramaterList != null) batchSize = paramaterList.size(); //学 JdbcTemplate 的public int[] batchUpdate(String sql, final BatchPreparedStatementSetter pss) if (JdbcUtils.supportsBatchUpdates(pstmt.getConnection())) { for (int i = 0; i < batchSize; i++) { List list = (List) paramaterList.get(i); int j = 1; for (Iterator iterator = list.iterator(); iterator.hasNext(); j++) { pstmt.setString(j, (String) iterator.next()); } pstmt.addBatch(); } return pstmt.executeBatch(); } else { List rowsAffected = new ArrayList(); for (int i = 0; i < batchSize; i++) { List list = (List) paramaterList.get(i); int j = 1; for (Iterator iterator = list.iterator(); iterator.hasNext(); j++) { pstmt.setString(j, (String) iterator.next()); } rowsAffected.add(new Integer(pstmt.executeUpdate())); } int[] rowsAffectedArray = new int[rowsAffected.size()]; for (int i = 0; i < rowsAffectedArray.length; i++) { rowsAffectedArray[i] = ((Integer) rowsAffected.get(i)).intValue(); } return rowsAffectedArray; } }