簡單JDBC封裝類
為什么要做這個封裝類:
以前經常使用Hibernate來操作數據庫,但是時間長了以后發現,Hibernate的大多數功能其實我根本就用不上,而且,Hibernate的查詢執行效率的確很讓人糾結
所以,我又回到了JDBC的懷抱,而我又是個懶人,喜歡一個函數就能直接調用的那種,JDBC本身方法對我來說,要打的字太多了...@_@
入正題:
首先,畫一個結構的草圖
包結構:
先貼代碼:
1.IConnectionProvider 接口
package org.sol.util.db; import java.sql.Connection; import java.sql.SQLException; /** * 用于獲取連接的接口 * @author SOL * */ public interface IConnectionProvider { public Connection getConnection(String sourceName) throws SQLException; }2.JDBCProvider JDBC數據提供源
package org.sol.util.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * 標準JDBC連接獲取代理 * @author HUYAO * */ public class JdbcProvider implements IConnectionProvider { private String DBDriver; private String DBUrl; private String username; private String password; public JdbcProvider(String DBDriver,String DBUrl,String username,String password) throws ClassNotFoundException { this.DBDriver = DBDriver; this.DBUrl = DBUrl; this.username = username; this.password = password; Class.forName(DBDriver); } @Override public Connection getConnection(String sourceName) throws SQLException { return DriverManager.getConnection(DBUrl + ";DatabaseName=" + sourceName,username,password); } public String getDBUrl() { return DBUrl; } public void setDBUrl(String dBUrl) { DBUrl = dBUrl; } public String getDBDriver() { return DBDriver; } public String getUsername() { return username; } public String getPassword() { return password; } }3.Tomcat數據提供源
package org.sol.util.db; import java.sql.Connection; import java.sql.SQLException; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; /** * TOMCAT JNDI連接池獲取代理 * @author SOL * */ public class TomcatProvider implements IConnectionProvider { @Override public Connection getConnection(String sourceName) throws SQLException { try { Context ctx = new InitialContext(); return ((DataSource)ctx.lookup("java:comp/env/" + sourceName)).getConnection(); } catch (Exception e) { throw new SQLException(e); } } }4.DataConsole 功能封裝類
package org.sol.util.db; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class DataConsole { /** * 連接 */ private Connection connection; /** * 預處理對象 */ private PreparedStatement ps; /** * 存儲過程處理對象 */ private CallableStatement cs; /** * 結果集對象 */ private ResultSet rs; /** * 數據源 */ private String sourceName; /** * 連接獲取代理 */ private IConnectionProvider connectionProvider; /** * 事務超時事件 */ private int queryTime; private static final Log log = LogFactory.getLog(DataConsole.class); /** * 生成一個JDBC封裝對象 * @param connectionProvider 連接提供代理 * @param sourceName 數據源名稱,connectionProvider根據此名稱切換數據源 * @param queryTime 事務處理超時時間 0:無超時 */ public DataConsole(IConnectionProvider connectionProvider,String sourceName,int queryTime) { this.connectionProvider = connectionProvider; this.sourceName = sourceName; this.queryTime = queryTime; } /** * 統計語句查詢 直接返回唯一值 * @param sql * @param objs * @return * @throws SQLException */ public Object findReturn(String sql,Object... objs) throws SQLException { log.debug("Query return value:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : "")); try { getConnection(); ps = connection.prepareStatement(sql); ps.setQueryTimeout(queryTime); if(objs != null) { for(int i = 0 ; i < objs.length; i ++) ps.setObject(i + 1, objs[i]); } rs = ps.executeQuery(); if(rs.next()) return rs.getObject(1); else return null; } finally { close(); } } /** * 執行存儲過程 首字段用于處理返回值 所以存儲過程寫法必須是 {?=call PRODUCENAME(?,?...,?)} * @param call 存儲過程 * @param returnType 返回參數類型 [Types.XXXX] * @param objs 參數列表 * @return * @throws SQLException */ public Object callWithReturn(String call,int returnType,Object... objs) throws SQLException { log.debug("Call return value:[" + call + "] " + (objs != null ? Arrays.deepToString(objs) : "")); try { getConnection(); cs = connection.prepareCall(call); cs.setQueryTimeout(queryTime); cs.registerOutParameter(1, returnType); for(int i = 0; i < objs.length; i ++) cs.setObject(i+2,objs[i]); cs.execute(); return cs.getObject(1); } finally { close(); } } /** * 用于執行返回列表的存儲過程 并映射到對象列表上 * @param <X> * @param clazz 映射對象 * @param sql 查詢語句 * @param smap 映射配置表<字段名,類型> * @param objs 參數列表 * @return * @throws Exception */ public <X> List<X> call(Class<X> clazz,String sql,Map<String,Class<?>> smap,Object... objs) throws Exception { log.debug("Call Query produce:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : "")); try { rs = call(sql, objs); List<X> list = new ArrayList<X>(); while(rs != null && rs.next()) { X obj = returnObject(clazz,smap); list.add(obj); } return list; } catch (Exception e) { close(); throw e; } finally { close(); } } private ResultSet call(String sql,Object... params) throws SQLException { getConnection(); cs = connection.prepareCall(sql,ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); cs.setQueryTimeout(queryTime); cs.registerOutParameter(1, Types.REAL); for(int i = 0; i < params.length; i ++) cs.setObject(i + 2, params[i]); return cs.executeQuery(); } /** * 查詢單個對象 并映射到對象上 * @param <X> * @param clazz 映射對象 * @param sql 查詢語句 * @param smap 映射配置表<字段名,類型> * @param objs 參數列表 * @return * @throws Exception */ public <X> X get(Class<X> clazz,String sql,Map<String,Class<?>> smap,Object... objs) throws SQLException { log.debug("Get Entity:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : "")); try { rs = query(sql, objs); if(rs != null && rs.next()) { X obj = returnObject(clazz,smap); return obj; } else { return null; } } catch (Exception e) { throw new SQLException(e); } finally { close(); } } private ResultSet query(String sql,Object... objs) throws Exception { getConnection(); ps = connection.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ps.setQueryTimeout(queryTime); if(objs != null) { for(int i = 0; i < objs.length; i ++) ps.setObject(i + 1, objs[i]); } return ps.executeQuery(); } /** * 用于解析查詢結果 并映射到對象 * @param <X> * @param clazz 映射對象 * @param smap 映射表 * @return * @throws InstantiationException * @throws SecurityException * @throws NoSuchMethodException * @throws SQLException * @throws IllegalAccessException */ private <X> X returnObject(Class<X> clazz,Map<String,Class<?>> smap) throws InstantiationException, SecurityException, NoSuchMethodException, SQLException, IllegalAccessException { X obj = clazz.newInstance(); for(Entry<String,Class<?>> en : smap.entrySet()) { try { Object value = rs.getObject(en.getKey()); setField(obj,en.getKey(),en.getValue(),(en.getValue().equals(String.class) ? (value != null ? value : null) : value)); } catch (IllegalArgumentException e1) { log.error("不正確的對象映射. 映射類:" + clazz.getName() + " 配置字段名:" + en.getKey() + " 類型:" + en.getValue().getName() + " 數據庫字段類型:" + rs.getObject(en.getKey()).getClass().getName()); } catch (InvocationTargetException e1) { e1.printStackTrace(); } } return obj; } /** * 設置對象上字段的值 * 現在只支持簡單的對象類型 String Integer Short Double 等標準對象 * 可以擴展這個方法用來支持一些比較復雜的對象格式 * @param obj 映射的對象 * @param fieldname 字段名稱 將調用它的set方法進行設置 * @param type 字段類型 * @param value 字段值 * @throws SecurityException * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ protected void setField(Object obj,String fieldname,Class<?> type,Object value) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method method = obj.getClass().getMethod(setMethod(fieldname),type); method.invoke(obj, value); } /** * 執行插入語句,并返回生成的主鍵 * @param sql 插入語句 * @param objs 參數列表 * @return 插入語句返回的主鍵值 * @throws SQLException */ public int insertAndReturnKey(String sql,Object... objs) throws SQLException { int countRow = 0; int key = 0; log.debug("Insert and return Id:[" + sql + "] " + (objs != null ? Arrays.deepToString(objs) : "")); try { getConnection(); connection.setAutoCommit(false); ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); ps.setQueryTimeout(queryTime); if(objs != null) { for(int i = 0; i < objs.length; i ++) ps.setObject(i+1,objs[i]); } countRow = ps.executeUpdate(); if(countRow > 0) { ResultSet rs = ps.getGeneratedKeys(); if(rs.next()) key = rs.getInt(1); } connection.commit(); } catch (SQLException e) { countRow = 0; connection.rollback(); closeConnection(); throw e; } finally { if (connection != null) { connection.setAutoCommit(true); } close(); } return key; } /** * 執行預編譯SQL * @param sql SQL語句 * @param objs 參數列表 * @return 執行影響條數 * @throws SQLException */ public int updatePrepareSQL(String sql,Object... objs) throws SQLException { log.debug("Update:[" + sql + "]" + (objs != null ? objs.toString() : "")); int countRow = 0; try { getConnection(); connection.setAutoCommit(false); ps = connection.prepareStatement(sql); ps.setQueryTimeout(queryTime); if(objs != null) { for(int i = 0; i < objs.length; i ++) ps.setObject(i+1,objs[i]); } countRow = ps.executeUpdate(); connection.commit(); } catch (SQLException e) { countRow = 0; connection.rollback(); closeConnection(); throw e; } finally { if (connection != null) { connection.setAutoCommit(true); } close(); } return countRow; } public <X> List<X> find(String sql,Class<X> clazz,Map<String,Class<?>> smap,Object... objs) throws SQLException { try { log.debug("Query:" + sql + " Class:" + clazz.getName() + (objs != null ? Arrays.deepToString(objs) : "")); rs = query(sql, objs); List<X> list = new ArrayList<X>(); while(rs != null && rs.next()) { X obj = returnObject(clazz,smap); list.add(obj); } return list; } catch (Exception e) { throw new SQLException(e); } finally { close(); } } public void closeConnection() { try { if (connection != null) { connection.close(); } connection = null; } catch (Exception e) { } } public Connection getConnection() throws SQLException { if(sourceName == null) throw new SQLException("沒有設置數據源"); int Times = 0; while (connection == null || connection.isClosed()) { try { closeConnection(); connection = connectionProvider.getConnection(sourceName); break; } catch (Exception sqle) { log.error("error getConnection():" + sqle.getMessage(),sqle); }finally{ if(Times>5){ throw new SQLException("獲取連接次數已經超過6次。不再嘗試重新獲取"); } ++Times; } } return connection; } public void close() { try { super.finalize(); if (rs != null) { rs.close(); rs = null; } if (ps != null) { ps.close(); ps = null; } if (cs != null) { cs.close(); cs = null; } if (connection != null) { connection.close(); connection = null; } } catch (Throwable te) { } } public static Map<String,Class<?>> parseSmap(Class<?> clazz,String... paramNames) { Map<String,Class<?>> smap = new HashMap<String, Class<?>>(paramNames.length); for(String name : paramNames) { try { Field field = clazz.getDeclaredField(name); smap.put(name, field.getType()); } catch (Exception e) { throw new RuntimeException(e); } } return smap; } public static String getMethod(String name) { return "get" + name.replaceFirst(name.substring(0,1), name.substring(0,1).toUpperCase()); } public static String setMethod(String name) { return "set" + name.replaceFirst(name.substring(0,1), name.substring(0,1).toUpperCase()); } }簡單介紹一下這個封裝類
封裝類通過ConnectionProvider獲取相應的數據源類型,提供幾個快速使用的JDBC方法,包括查詢,更新語句,插入并返回主鍵,調用存儲過程等幾個常用方法,可以看源文件里的說明
用一個測試類來說明吧
package org.sol.util.db; import java.sql.SQLException; import java.sql.Types; public class test { private IConnectionProvider connectionProvider = null; private String sourceName = "megajoysms"; private int queryTime = 5; private DataConsole dc; public test() { /* * 首先建立數據源對象,現在演示的使用的是JDBC提供源 * 三個參數 1.驅動名稱 2.url(數據庫名不需要填寫,由sourceName參數執行) 3.登錄用戶名 4.密碼 * 代碼中還提供了一個tomcat的jndi數據提供源,其他類似的源可以直接繼承IConnectionProvider接口實現 */ try { connectionProvider = new JdbcProvider( "com.microsoft.sqlserver.jdbc.SQLServerDriver", "jdbc:sqlserver://127.0.0.1:1433", "sa","123456"); } catch (ClassNotFoundException e) { e.printStackTrace(); } dc = new DataConsole(connectionProvider, sourceName, queryTime); } /** * Find 方法用來查詢對象 * 接收3+ 個參數 * 第一個參數表示執行的Select語句 * 第二個參數表示查詢結果映射到一個對象類型上 * 第三個參數表示對查詢結果字段的映射關系 * 第四個字段用于如果SQL語句是帶參數的,從這里開始填入變量列表 * * 數據表test結構 * int id, * varchar text, * varchar value * 映射對象結構 * class pojo { private Integer id; private String text; get/set 方法... } * 第三個參數的類型是Map<String,Class<?>>表示 字段名-字段類型的映射關系 * 可以自己建立這個map,map的鍵用來匹配查詢結果集的字段及映射類的字段 * 也可以用DataConsole.parseSmap(Class,String...)方法獲取map * 這個函數接收兩個參數,第一個參數表示映射的類型,第二個開始的參數表示字段名稱,函數會在映射類中匹配相應的字段類型 * PS:映射類內部的字段類型不能是基礎類型比如int,short,要寫成Integer,Short */ public void find() { try { System.out.println(dc.find( "select top 10 * from test where id>?", pojo.class, DataConsole.parseSmap(pojo.class, "id","whichservice"), 10)); } catch (SQLException e) { e.printStackTrace(); } } /** * 執行更新語句的方法 * 接收1+個參數 * 第一個參數表示SQL更新語句 * 第二個以后的參數表示傳入的變量列表,無參數語句不填這些參數 * 返回結果是查詢影響的記錄條數 */ public void update() { try { System.out.println(dc.updatePrepareSQL( "insert into test(id,text,value) values(?,?,?)", 1,"text","value")); } catch (SQLException e) { e.printStackTrace(); } } /** * 執行插入動作,并返回這個操作記錄的主鍵,如果操作無主鍵或主鍵不是自增型,返回0 * 參數類似于更新動作,這里演示了沒有sql變量的情況 */ public void insertAndReturnKey() { try { System.out.println(dc.insertAndReturnKey("insert into test(text,value) values('text','value')")); } catch (SQLException e) { e.printStackTrace(); } } /** * 類似于執行select語句,此方法用于執行帶有返回結果集的存儲過程 */ public void callAndReturnResultSet() { try { System.out.println(dc.call(pojo.class, "{call proc_returnpojo(?)}", DataConsole.parseSmap(pojo.class, "id","whichservice"), 1)); } catch (Exception e) { e.printStackTrace(); } } /** * 用于執行存儲過程,如果存儲過程帶有返回值(非output參數),返回接受到的返回值 * 首字段用于處理返回值 所以存儲過程寫法必須是 {?=call PRODUCENAME(?,?...,?)} * 比如: * create proc_testreturn * begin * return 1 * end */ public void callAndReturn() { try { System.out.println(dc.callWithReturn("{?=call proc_testreturn}", Types.INTEGER)); } catch (SQLException e) { e.printStackTrace(); } } }其中用到的pojo類的定義:
package org.sol.util.db; public class pojo { private Integer id; private String text; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } @Override public String toString() { return "pojo [" + (id != null ? "id=" + id + ", " : "") + (text != null ? "text=" + text : "") + "]"; } }
本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!