在学框架之前,写项目时总是要花大量的时间去写数据库操作层代码,这样会大大降低我们的效率,为了解决这个问题,我花了两天时间利用反射机制和泛型将DAO层进行了封装,这样我们只需要写sql语句,不需要再写繁琐的数据库操作语句,增强代码的复用性,让我们把主要精力放在业务逻辑上。
以下就是我写的代码(我是用连接池操作,普通的jdbc操作和连接池道理相同,主要思想是将结果集设置到对象的属性中)
1 /** 2 * 预处理通用查询对象集合 3 * 4 * @param cla 操作类型 5 * @param params 预处理参数 6 * @param sql 要执行的sql语句 7 * @return 返回的对象集合 8 * @throws SQLException 抛出异常 9 */ 10 @SuppressWarnings("deprecation") 11 public static <T> List<T> commonPreparedQueryList(final Class<T> cla,Object params[],String sql) throws SQLException{ 12 //获得连接池(这里使用的是阿里巴巴开源的jar包) 13 QueryRunner qr = new QueryRunner(DBUtil.getDruid()); 14 /* 15 * 声明一个List存放返回对象 16 */ 17 List<T> tList = new ArrayList<T>(); 18 /* 19 * 执行查询操作并返回对应集合,传入sql和预处理参数并进行结果集处理(这里要实现handle方法) 20 */ 21 tList = qr.query(sql, params,new ResultSetHandler<List<T>>(){ 22 23 public List<T> handle(ResultSet rs) throws SQLException { 24 /* 25 * 这里要用到ResultSetMetaData来获取数据库表的字段名和数量 26 */ 27 ResultSetMetaData ms = rs.getMetaData(); 2 T t = null;//声明一个泛型,此处类型和传入一致 29 List<T> list = new ArrayList<T>(); 30 /* 31 * 通过循环获得表中所有的字段名,并通过反射的方式把字段名内容 32 * 设置到我们要查询的集合中,并将结果返回 33 * 注意:这里需要用到循环的嵌套,我们需要先循环表中所有数据, 34 * 然后再循环表的所有字段名 35 */ 36 while(rs.next()){ 37 try { 38 t = cla.newInstance();//创建一个实例化对象 39 //获得所有字段名,并将其转换为驼峰式命名规则 eg:guest_id转化为guestId 40 for(int i = 0; i <ms.getColumnCount(); i++){ 41 String columnName = ms.getColumnName(i+1);//获得字段名 42 /* 43 * 以下操作是将下划线形式转化为驼峰式的实现 44 * 现将字段名以下划线分割到字符串数组中,将第一个数组元素复制到StringBuffer中 45 * 然后将后面的数组元素第一个首字母转化为大写形式,最后将他们拼接到一起,将所得结果转化为字符串 46 */ 47 String[] strName = columnName.split("_"); 48 StringBuffer sb = new StringBuffer(strName[0]); 49 for(int i1 = 1;i1<strName.length;i1++){ 50 strName[i1] = strName[i1].substring(0, 1).toUpperCase().concat(strName[i1].substring(1)); 51 sb.append(strName[i1]); 52 } 53 String property = sb.toString(); 54 /* 55 * 获得对象的所有属性,并将结果集中的内容通过反射赋值到对象的属性中 56 */ 57 Field field = cla.getDeclaredField(property); 58 field.setAccessible(true); 59 field.set(t, rs.getObject(columnName)); 60 } 61 } catch (InstantiationException e) { 62 e.printStackTrace(); 63 } catch (IllegalAccessException e) { 64 e.printStackTrace(); 65 } catch (NoSuchFieldException e) { 66 e.printStackTrace(); 67 } catch (SecurityException e) { 68 e.printStackTrace(); 69 } 70 //将对象添加到List中 71 list.add(t); 72 } 73 //循环结束后返回对象集合 74 return list; 75 } 76 77 }); 78 return tList; 79 }
测试代码:
1 public void Test() throws SQLException{ 2 List<Book> bookList = new LinkedList<Book>(); 3 Object params[] = new Object[]{"%三%"}; 4 String sql = "select * from book where book_name like ? "; 5 bookList = CommonDao.commonPreparedQueryList(Book.class,params ,sql); 6 System.out.println(bookList); 7 }
一共两条数据
查询一条数据(这个和查询集合的区别只有集合需要循环结果集,而这个只需要用if语句判断一下即可,其余代码完全相同):
1 /** 2 * 通用预处理查询对象 3 * 4 * @param cla 5 * @param params 6 * @param sql 7 * @return 对象 8 * @throws SQLException 9 * @throws InstantiationException 10 * @throws IllegalAccessException 11 */ 12 @SuppressWarnings("deprecation") 13 public static <T> T commonPreparedQuery(final Class<T> cla,Object params[],String sql) throws SQLException, InstantiationException, IllegalAccessException{ 14 QueryRunner qr = new QueryRunner(DBUtil.getDruid()); 15 T m = cla.newInstance(); 16 m = qr.query(sql,params ,new ResultSetHandler<T>(){ 17 18 public T handle(ResultSet rs) throws SQLException { 19 ResultSetMetaData rm = rs.getMetaData(); 20 T t = null; 21 try { 22 if(rs.next()){ //这里用if,是与查询集合代码的唯一区别 23 t = cla.newInstance(); 24 for(int i = 0; i<rm.getColumnCount(); i++){ 25 String columnName = rm.getColumnName(i+1); 26 String str[] = columnName.split("_"); 27 StringBuffer sb = new StringBuffer(str[0]); 28 for(int j = 1; j<str.length; j++){ 29 str[j] = str[j].substring(0, 1).toUpperCase().concat(str[j].substring(1)); 30 sb.append(str[j]); 31 } 32 String property = sb.toString(); 33 Field field = cla.getDeclaredField(property); 34 field.setAccessible(true); 35 field.set(t, rs.getObject(columnName)); 36 } 37 }else{ 38 System.out.println("sql语句错误或对象不存在"); 39 } 40 } catch (InstantiationException e) { 41 e.printStackTrace(); 42 } catch (IllegalAccessException e) { 43 e.printStackTrace(); 44 } catch (SecurityException e) { 45 e.printStackTrace(); 46 } catch (NoSuchFieldException e) { 47 e.printStackTrace(); 48 } 49 return t; 50 } 51 52 }); 53 return m; 54 }
测试:
public void Test() throws SQLException, InstantiationException, IllegalAccessException{ Book book = new Book(); Object params[] = new Object[]{10001}; String sql = "select * from book where book_id = ? "; book = CommonDao.commonPreparedQuery(Book.class, params, sql); System.out.println(book); }
还有普通查询操作(不通过预处理)
这种方式和预处理查询的唯一区别只是不需要传递参数params,其余和上面代码完全一致
1 /** 2 * 通用类查询集合 3 * 4 * @param cla 5 * @param sql 6 * @return 7 * @throws SQLException 8 */ 9 public static <T> List<T> commonQueryList(final Class<T> cla,String sql) throws SQLException{ 10 QueryRunner qr = new QueryRunner(DBUtil.getDruid()); 11 List<T> tList = new ArrayList<T>(); 12 tList = qr.query(sql, new ResultSetHandler<List<T>>(){ 13 14 public List<T> handle(ResultSet rs) throws SQLException { 15 ResultSetMetaData ms = rs.getMetaData(); 16 T t = null; 17 List<T> list = new ArrayList<T>(); 18 while(rs.next()){ 19 try { 20 t = cla.newInstance(); 21 for(int i = 0; i <ms.getColumnCount(); i++){ 22 String columnName = ms.getColumnName(i+1); 23 String[] strName = columnName.split("_"); 24 StringBuffer sb = new StringBuffer(strName[0]); 25 for(int i1 = 1;i1<strName.length;i1++){ 26 strName[i1] = strName[i1].substring(0, 1).toUpperCase().concat(strName[i1].substring(1)); 27 sb.append(strName[i1]); 28 } 29 String property = sb.toString(); 30 Field field = cla.getDeclaredField(property); 31 field.setAccessible(true); 32 field.set(t, rs.getObject(columnName)); 33 } 34 } catch (InstantiationException e) { 35 e.printStackTrace(); 36 } catch (IllegalAccessException e) { 37 e.printStackTrace(); 38 } catch (NoSuchFieldException e) { 39 e.printStackTrace(); 40 } catch (SecurityException e) { 41 e.printStackTrace(); 42 } 43 list.add(t); 44 } 45 return list; 46 } 47 48 }); 49 return tList; 50 }
测试:
public void Test() throws SQLException{ List<Book> bookList = new LinkedList<Book>(); String sql = "select * from book "; bookList = CommonDao.commonQueryList(Book.class,sql); System.out.println(bookList); }
同样有两条数据
查询一个对象:
1 /** 2 * 查询一个数据库类操作 3 * 4 * @param cla 5 * @param sql 6 * @return 一个数据库类对象 7 * @throws SQLException 8 * @throws InstantiationException 9 * @throws IllegalAccessException 10 */ 11 public static <T> T commonQuery(final Class<T> cla,String sql) throws SQLException, InstantiationException, IllegalAccessException{ 12 QueryRunner qr = new QueryRunner(DBUtil.getDruid()); 13 T m = cla.newInstance(); 14 m = qr.query(sql, new ResultSetHandler<T>(){ 15 16 public T handle(ResultSet rs) throws SQLException { 17 ResultSetMetaData rm = rs.getMetaData(); 18 T t = null; 19 try { 20 if(rs.next()){ 21 t = cla.newInstance(); 22 for(int i = 0; i<rm.getColumnCount(); i++){ 23 String columnName = rm.getColumnName(i+1); 24 String str[] = columnName.split("_"); 25 StringBuffer sb = new StringBuffer(str[0]); 26 for(int j = 1; j<str.length; j++){ 27 str[j] = str[j].substring(0, 1).toUpperCase().concat(str[j].substring(1)); 28 sb.append(str[j]); 29 } 30 String property = sb.toString(); 31 Field field = cla.getDeclaredField(property); 32 field.setAccessible(true); 33 field.set(t, rs.getObject(columnName)); 34 } 35 }else{ 36 System.out.println("sql语句错误或对象不存在"); 37 } 38 } catch (InstantiationException e) { 39 e.printStackTrace(); 40 } catch (IllegalAccessException e) { 41 e.printStackTrace(); 42 } catch (SecurityException e) { 43 e.printStackTrace(); 44 } catch (NoSuchFieldException e) { 45 e.printStackTrace(); 46 } 47 return t; 48 } 49 50 }); 51 return m; 52 }
测试:
@Test public void Test() throws SQLException, InstantiationException, IllegalAccessException{ Book book = new Book(); String sql = "select * from book where book_id = 10002"; book = CommonDao.commonQuery(Book.class,sql); System.out.println(book); }
接下来是增删改操作,这个操作比较简单,不需要用到泛型和反射,只需要传入sql语句即可:
1 public static boolean updateSql(String sql) throws SQLException{ 2 boolean flag = false; 3 QueryRunner qr = new QueryRunner(DBUtil.getDruid());
//执行修改操作 4 if(qr.update(sql)>0) 5 flag = true; 6 return flag; 7 }
还有预处理形式
1 public static boolean updatePreparedSql(String sql,Object params[]) throws SQLException{ 2 boolean flag = false; 3 QueryRunner qr = new QueryRunner(DBUtil.getDruid()); 4 if(qr.update(sql,params)>0) 5 flag = true; 6 return flag; 7 }
还有批量处理形式
/** * 通过预处理解决批量增删改操作 * * @param sql * @param params params[rows][cols],rows代表sql语句执行次数,cols表示替换占位符的参数个数 * @return boolean * @throws SQLException */ public static boolean batchProcessing(String sql,Object params[][]) throws SQLException{ boolean flag = false; QueryRunner qr = new QueryRunner(DBUtil.getDruid()); if(qr.batch(sql, params).length == params.length) flag = true; return flag; }