JDBC的简单封装
JDBC的简单封装
使用JDBC来处理数据库的接口主要有三个,即Connection,PreparedStatement和ResultSet这三个,而对于这三个接口,还可以获取不同类型的元数据,通过这些元数据类获得一些数据库的信息。
元数据(MetaData),即定义数据的数据。打个比方,就好像我们要想搜索一首歌(歌本身是数据),而我们可以通过歌名,作者,专辑等信息来搜索,那么这些歌名,作者,专辑等等就是这首歌的元数据。因此数据库的元数据就是一些注明数据库信息的数据。
① 由Connection对象的getMetaData()方法获取的是DatabaseMetaData对象。
② 由PreparedStatement对象的getParameterMetaData ()方法获取的是ParameterMetaData对象。
③由ResultSet对象的getMetaData()方法获取的是ResultSetMetaData对象。
今天仅仅使用第二点,所以就解释一下第二点
ParameterMetaData是由PreparedStatement对象通过getParameterMetaData方法获取而来,主要是针对PreparedStatement对象和其预编译的SQL命令语句提供一些信息,比如像”insert into account(id,name,money) values(?,?,?)”这样的预编译SQL语句,ParameterMetaData能提供占位符参数的个数,获取指定位置占位符的SQL类型等等,功能也比较多,这里不列举完,详细请看有关ParameterMetaData的API文档。
Eg: getParameterCount:获取预编译SQL语句中占位符参数的个数
下面就是贴代码了:封装了几个类(类中对功能做了详细的说明)
第一个类:CommonDao 封装了对JDBC的获取连接和连接关闭, 查询和更新功能
package jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ParameterMetaData; 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.List; import java.util.Map; public class CommonDAO { // 数据库连接url private static final String url = "jdbc:mysql://localhost:3306/test?Unicode=true&characterEncoding=UTF-8"; // 数据库连接用户名 private static final String username = "root"; // 数据库连接密码 private static final String password = "root"; // 数据库驱动 private static final String jdbcDriver = "com.mysql.jdbc.Driver"; // 调用 ParameterMetaData.getParameterType(i + 1) 是否会抛出异常 protected boolean pmdKnownBroken = false; public CommonDAO() { } public CommonDAO(boolean pmdKnownBroken) { this.pmdKnownBroken = pmdKnownBroken; } // 获取连接 public Connection getConnetion() { Connection conn = null; try { Class.forName(jdbcDriver); conn = DriverManager.getConnection(url, username, password); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return conn; } /** * @Title: executeQuery * @Description: 执行Sql 查询语句,把结果集合放在一个 List<Map<String,Object>> 里面 * @param sql * @param parmas * @return * @return List<Map<String,Object>> */ @SuppressWarnings("unchecked") public List<Map<String, Object>> executeQuery(String sql, Object[] params) { return (List<Map<String, Object>>) this.excuteQuery(sql, params, new ListMapHander()); } /** * @Title: excuteQuery * @Description: 查询给定的SQL语句,并且自定义的处理结果集。 调用者需要自己手动实现 * 接口<code>ResultSetHander.doHander(ResultSet rs)</code> * 方法以得结果集里面的数据 * @param sql * @param params * @param rsh * @return * @return Object */ public Object excuteQuery(String sql, Object[] params, ResultSetHander rsh) { PreparedStatement stmt = null; ResultSet rs = null; Connection con = this.getConnetion(); List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(); try { stmt = con.prepareStatement(sql); System.out.println("SQL:" + sql + "; Parameters:" + Arrays.deepToString(params)); // 填充Statement的参数 fillStatement(stmt, params); // 执行查询 rs = stmt.executeQuery(); Object obj = rsh.doHander(rs); return obj; } catch (SQLException e) { e.printStackTrace(); } finally { // 关闭数据库连接 close(con, stmt, rs); } return resultList; } public int executeUpdate(String sql, Object[] params) { PreparedStatement stmt = null; Connection con = this.getConnetion(); int rs = 0; try { con.setAutoCommit(false); // 创建PreparedStatement对象 stmt = con.prepareStatement(sql); // 填充Statement的参数 fillStatement(stmt, params); System.out.println("SQL:" + sql + "; Parameters:" + Arrays.deepToString(params)); // 执行查询 rs = stmt.executeUpdate(); // 提交事务 con.commit(); // 把事务设置为原来的 con.setAutoCommit(true); } catch (SQLException e) { // 在捕获到异常的时候事务回滚 try { con.rollback(); if (!con.getAutoCommit()) { con.setAutoCommit(true); } } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { // 关闭数据库连接 close(con, stmt, null); } return rs; } /** * @Title: fillStatement * @Description: 填充SQL参数 * @param stmt * @param params * @throws SQLException * @return void */ private void fillStatement(PreparedStatement stmt, Object[] params) throws SQLException { // 检测参数的个数是否合法,但是有的数据库驱动不支持 stmt.getParameterMetaData()这个方法。 // 因此我们有一个一个pmdKnownBroken 变量来标识当前数据驱动是否支持该方法的调用。 ParameterMetaData pmd = null; if (!pmdKnownBroken) { pmd = stmt.getParameterMetaData(); int stmtCount = pmd.getParameterCount(); int paramsCount = params == null ? 0 : params.length; if (stmtCount != paramsCount) { System.out.println("stmtCount:" + stmtCount + ",paramsCount:" + paramsCount); throw new SQLException( "Wrong number of parameters: expected " + stmtCount + ", was given " + paramsCount); } } // 如果 params 为 null 直接返回 if (params == null) { return; } for (int i = 0; i < params.length; i++) { if (params[i] != null) { stmt.setObject(i + 1, params[i]); } else { int sqlType = Types.VARCHAR; if (!pmdKnownBroken) { try { sqlType = pmd.getParameterType(i + 1); } catch (SQLException e) { pmdKnownBroken = true; } } stmt.setNull(i + 1, sqlType); } } } /** * @Title: close * @Description: 关闭数据库连接 * @param con * @param stmt * @param rs * @return void */ private void close(Connection con, Statement stmt, ResultSet rs) { if (rs != null) { try { rs.close(); } catch (Exception e) { } finally { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } finally { if (con != null) { try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } } } } } } }
下面是自封装集合处理类:
package jdbc; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ListMapHander implements ResultSetHander { @Override public List<Map<String, Object>> doHander(ResultSet rs) throws SQLException { List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(); ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); HashMap<String, Object> m = null; // System.out.println("list 结果:"); // 遍历结果集 while (rs.next()) { m = new HashMap<String, Object>(); // 将结果集中的数据保存到HashMap中 for (int i = 1; i <= cols; i++) { System.out.println("Label:" + rsmd.getColumnLabel(i)); System.out.println(rsmd.getColumnName(i) + "," + rs.getObject(i)); m.put(rsmd.getColumnLabel(i), rs.getObject(i)); } resultList.add(m); } return resultList; } }
数据处理接口类:
package jdbc; import java.sql.ResultSet; import java.sql.SQLException; public interface ResultSetHander { //自定义处理结果集 public Object doHander(ResultSet rs) throws SQLException; }
实现上面的接口类:
package jdbc; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ListMapHander implements ResultSetHander { @Override public List<Map<String, Object>> doHander(ResultSet rs) throws SQLException { List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(); ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); HashMap<String, Object> m = null; // System.out.println("list 结果:"); // 遍历结果集 while (rs.next()) { m = new HashMap<String, Object>(); // 将结果集中的数据保存到HashMap中 for (int i = 1; i <= cols; i++) { System.out.println("Label:" + rsmd.getColumnLabel(i)); System.out.println(rsmd.getColumnName(i) + "," + rs.getObject(i)); m.put(rsmd.getColumnLabel(i), rs.getObject(i)); } resultList.add(m); } return resultList; } }
下面是测试类:数据以Objcet对象数组的形式传入, 利用占位符。
package jdbc; public class Test { public static void main(String[] args) { CommonDAO commonDAO = new CommonDAO(); String sql = "select * from student"; commonDAO.executeQuery(sql, null); /*commonDAO.executeUpdate("insert into student values (?,?,?,?,?)", new Object[] { "210", "彭宇", "男", "1995-02-02", "955330" });*/ } }