標籤:shm override update time 類型 開發效率 動態代理模式 代碼 cti
DBUtils大大簡化了JDBC的書寫,極大的提高了開發效率,和資料庫連接池一起,簡化了JDBC開發的流程.簡易的自訂資料庫連接池可以通過裝飾者設計模式和動態代理模式得到很簡單的實現,那麼DBUtils應該怎麼實現呢?為了瞭解DBUtils其內部工作的流程,我實現了一個自己的DBUtils工具類,實現一些簡單的更新和查詢操作.
ResultSetMetaData是可以擷取ResultSet對象的列類型和屬性資訊的對象.這個類裡面有很多方法,在這個案例中,只用到兩個:getColumnCount():擷取ResultSet結果集中列的數目.getColumnName(int column):根據指定的列數目擷取列名.有了這兩個方法就可以自己動手去實現一個簡易版的DBUtils啦~下面是我實現的步驟:
1.編寫MyQueryRunner的executeUpdate方法.
這個方法的編寫非常簡單,因為可以通過dataSource擷取Connection,在方法的內部就是簡單的jdbc操作.需要注意的是,需要手動設定傳入的參數到PreparedStatement中.代碼如下:
public int update(String sql, Object... params) { Connection connection=null; PreparedStatement preparedStatement=null; try { connection=dataSource.getConnection(); preparedStatement=connection.prepareStatement(sql); for(int i=0;i<params.length;i++) { preparedStatement.setObject((i+1), params[i]);//設定參數. } int x=preparedStatement.executeUpdate();//執行更新操作. return x; } catch (SQLException e) { throw new RuntimeException(e); } finally { if(preparedStatement!=null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
2.編寫MyQueryRunner的executeQuery方法.
這個方法的實現也不難,因為我們將重要的代碼交給傳入的ResultSetHandler實現對象來處理.代碼如下:
//查詢會比較麻煩. //作出三個實現BeanHandler BeanListHandler MapListHandler public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) { Connection connection=null; PreparedStatement preparedStatement=null; ResultSet rs=null; try { connection=dataSource.getConnection(); preparedStatement=connection.prepareStatement(sql); if(params!=null) { for(int i=0;i<params.length;i++) { preparedStatement.setObject((i+1), params[i]); } } rs=preparedStatement.executeQuery(); return rsh.handle(rs);//交給處理器處理 } catch (SQLException e) { throw new RuntimeException(e); } finally { if(rs!=null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(preparedStatement!=null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection!=null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
3.3個處理器的編寫.
在MyQueryRunner實現自訂查詢的實現中,我實現了三個處理器,它們分別是採用了BeanHandler,BeanListHandler,MapListHandler的實現思想,並且給出了最簡單易懂(實際上是因為我水平不夠= =)的實現.下面說說BeanHandler的實現流程,Handler的實現基本上都是一樣的,無非是採用反射獲得元素對象,並且將資料封裝進去.
BeanHandler中有兩個成員變數,一個T t用來作為要返回的JavaBean,聲明在外面供之後封裝資料使用,一個Class type對象,用來擷取Class,建立JavaBean對象賦值給t,建立Field對象為t的成員變數賦值.在方法的實現中,先通過getColumnCount方法來擷取列的數目,遍曆每一列,通過getColumnName(int columnCount)方法擷取列名,用Class對象的getField方法擷取Field對象(這裡JavaBean的取值一定要和資料庫中相同!否則會報錯),再利用Field對象的set方法賦值.當然Field對象對應的成員變數一定是私人的(JavaBean的特性.)因此需要先調用setAccessable方法才可以.具體的代碼如下:
public class MyBeanHandler<T> implements ResultSetHandler{ private Class<T> type; T t;//需要封裝的JavaBean public MyBeanHandler(Class<T> type) { this.type=type; } @Override public Object handle(ResultSet rs) throws SQLException { try { t=type.newInstance(); ResultSetMetaData metaData = rs.getMetaData(); int count=metaData.getColumnCount();//擷取ResultSet中資料的列數 rs.next();//移動指標 //遍曆獲的每一列的列名,採用反射機制設定值 for(int i=1;i<=count;i++) { String name=metaData.getColumnName(i); Object obj=rs.getObject(i); Field field = type.getDeclaredField(name); field.setAccessible(true); field.set(t, obj);//封裝資料進入JavaBean } } catch (Exception e) { e.printStackTrace(); } return t; }}
MyBeanListHandler的實現步驟,基本和BeanHandler一致.唯一的區別就是採用結果集的next方法遍曆每一條記錄,而將對象的建立移動到了迴圈裡,這裡考慮返回的List對象的增刪應該比較少因此採用的是ArrayList.具體實現如下:
public class MyBeanListHandler<T> implements ResultSetHandler<List<T>>{ private Class<T> type; List<T> list=new ArrayList<T>();//可能擷取比較多.因此採用ArrayList public MyBeanListHandler(Class<T> type) { this.type = type; } @Override public List<T> handle(ResultSet rs) throws SQLException { try { ResultSetMetaData metaData = rs.getMetaData(); int count=metaData.getColumnCount(); while(rs.next()) { T t=type.newInstance(); for(int i=1;i<=count;i++) { String name=metaData.getColumnName(i);//該方法擷取列名.擷取一數列欄位名稱.例如name,age... Object obj=rs.getObject(i);//擷取欄位值 Field field = type.getDeclaredField(name);//擷取field對象 field.setAccessible(true); field.set(t, obj);//設定值 } list.add(t); } return list; } catch (Exception e) { throw new RuntimeException(e); } }}
MapList看上去似乎最複雜,但是實際上實現起來卻由於沒有採用泛型和反射,是最方便的,代碼如下:
public class MyMapListHandler implements ResultSetHandler<List<Map<String, Object>>> { private List<Map<String,Object>> data=new ArrayList<>(); @Override public List<Map<String, Object>> handle(ResultSet rs) throws SQLException { ResultSetMetaData metaData = rs.getMetaData(); int count=metaData.getColumnCount(); while(rs.next()) { Map<String,Object> map=new HashMap<>(); for(int i=1;i<=count;i++) { Object value=rs.getObject(i); String name=metaData.getColumnName(i); map.put(name, value); } data.add(map); } return data; }}
利用反射和ResultSetMetaData實現DBUtils的準系統