通过对DAO层的封装减少数据库操作的代码量

时间:2023-03-10 00:16:11
通过对DAO层的封装减少数据库操作的代码量

   在学框架之前,写项目时总是要花大量的时间去写数据库操作层代码,这样会大大降低我们的效率,为了解决这个问题,我花了两天时间利用反射机制和泛型将DAO层进行了封装,这样我们只需要写sql语句,不需要再写繁琐的数据库操作语句,增强代码的复用性,让我们把主要精力放在业务逻辑上。

  以下就是我写的代码(我是用连接池操作,普通的jdbc操作和连接池道理相同,主要思想是将结果集设置到对象的属性中)

     /**
* 预处理通用查询对象集合
*
* @param cla 操作类型
* @param params 预处理参数
* @param sql 要执行的sql语句
* @return 返回的对象集合
* @throws SQLException 抛出异常
*/
@SuppressWarnings("deprecation")
public static <T> List<T> commonPreparedQueryList(final Class<T> cla,Object params[],String sql) throws SQLException{
//获得连接池(这里使用的是阿里巴巴开源的jar包)
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
/*
* 声明一个List存放返回对象
*/
List<T> tList = new ArrayList<T>();
/*
* 执行查询操作并返回对应集合,传入sql和预处理参数并进行结果集处理(这里要实现handle方法)
*/
tList = qr.query(sql, params,new ResultSetHandler<List<T>>(){ public List<T> handle(ResultSet rs) throws SQLException {
/*
* 这里要用到ResultSetMetaData来获取数据库表的字段名和数量
*/
ResultSetMetaData ms = rs.getMetaData();
2              T t = null;//声明一个泛型,此处类型和传入一致
List<T> list = new ArrayList<T>();
/*
* 通过循环获得表中所有的字段名,并通过反射的方式把字段名内容
* 设置到我们要查询的集合中,并将结果返回
* 注意:这里需要用到循环的嵌套,我们需要先循环表中所有数据,
* 然后再循环表的所有字段名
*/
while(rs.next()){
try {
t = cla.newInstance();//创建一个实例化对象
//获得所有字段名,并将其转换为驼峰式命名规则 eg:guest_id转化为guestId
for(int i = 0; i <ms.getColumnCount(); i++){
String columnName = ms.getColumnName(i+1);//获得字段名
/*
* 以下操作是将下划线形式转化为驼峰式的实现
* 现将字段名以下划线分割到字符串数组中,将第一个数组元素复制到StringBuffer中
* 然后将后面的数组元素第一个首字母转化为大写形式,最后将他们拼接到一起,将所得结果转化为字符串
*/
String[] strName = columnName.split("_");
StringBuffer sb = new StringBuffer(strName[0]);
for(int i1 = 1;i1<strName.length;i1++){
strName[i1] = strName[i1].substring(0, 1).toUpperCase().concat(strName[i1].substring(1));
sb.append(strName[i1]);
}
String property = sb.toString();
/*
* 获得对象的所有属性,并将结果集中的内容通过反射赋值到对象的属性中
*/
Field field = cla.getDeclaredField(property);
field.setAccessible(true);
field.set(t, rs.getObject(columnName));
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
//将对象添加到List中
list.add(t);
}
//循环结束后返回对象集合
return list;
} });
return tList;
}

测试代码:

 public void Test() throws SQLException{
List<Book> bookList = new LinkedList<Book>();
Object params[] = new Object[]{"%三%"};
String sql = "select * from book where book_name like ? ";
bookList = CommonDao.commonPreparedQueryList(Book.class,params ,sql);
System.out.println(bookList);
}

通过对DAO层的封装减少数据库操作的代码量

通过对DAO层的封装减少数据库操作的代码量

一共两条数据

查询一条数据(这个和查询集合的区别只有集合需要循环结果集,而这个只需要用if语句判断一下即可,其余代码完全相同):

 /**
* 通用预处理查询对象
*
* @param cla
* @param params
* @param sql
* @return 对象
* @throws SQLException
* @throws InstantiationException
* @throws IllegalAccessException
*/
@SuppressWarnings("deprecation")
public static <T> T commonPreparedQuery(final Class<T> cla,Object params[],String sql) throws SQLException, InstantiationException, IllegalAccessException{
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
T m = cla.newInstance();
m = qr.query(sql,params ,new ResultSetHandler<T>(){ public T handle(ResultSet rs) throws SQLException {
ResultSetMetaData rm = rs.getMetaData();
T t = null;
try {
if(rs.next()){ //这里用if,是与查询集合代码的唯一区别
t = cla.newInstance();
for(int i = 0; i<rm.getColumnCount(); i++){
String columnName = rm.getColumnName(i+1);
String str[] = columnName.split("_");
StringBuffer sb = new StringBuffer(str[0]);
for(int j = 1; j<str.length; j++){
str[j] = str[j].substring(0, 1).toUpperCase().concat(str[j].substring(1));
sb.append(str[j]);
}
String property = sb.toString();
Field field = cla.getDeclaredField(property);
field.setAccessible(true);
field.set(t, rs.getObject(columnName));
}
}else{
System.out.println("sql语句错误或对象不存在");
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return t;
} });
return m;
}

测试:

    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);
}

通过对DAO层的封装减少数据库操作的代码量

还有普通查询操作(不通过预处理)

这种方式和预处理查询的唯一区别只是不需要传递参数params,其余和上面代码完全一致

 /**
* 通用类查询集合
*
* @param cla
* @param sql
* @return
* @throws SQLException
*/
public static <T> List<T> commonQueryList(final Class<T> cla,String sql) throws SQLException{
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
List<T> tList = new ArrayList<T>();
tList = qr.query(sql, new ResultSetHandler<List<T>>(){ public List<T> handle(ResultSet rs) throws SQLException {
ResultSetMetaData ms = rs.getMetaData();
T t = null;
List<T> list = new ArrayList<T>();
while(rs.next()){
try {
t = cla.newInstance();
for(int i = 0; i <ms.getColumnCount(); i++){
String columnName = ms.getColumnName(i+1);
String[] strName = columnName.split("_");
StringBuffer sb = new StringBuffer(strName[0]);
for(int i1 = 1;i1<strName.length;i1++){
strName[i1] = strName[i1].substring(0, 1).toUpperCase().concat(strName[i1].substring(1));
sb.append(strName[i1]);
}
String property = sb.toString();
Field field = cla.getDeclaredField(property);
field.setAccessible(true);
field.set(t, rs.getObject(columnName));
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
list.add(t);
}
return list;
} });
return tList;
}

测试:

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);
}

通过对DAO层的封装减少数据库操作的代码量

通过对DAO层的封装减少数据库操作的代码量

同样有两条数据

查询一个对象:

 /**
* 查询一个数据库类操作
*
* @param cla
* @param sql
* @return 一个数据库类对象
* @throws SQLException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public static <T> T commonQuery(final Class<T> cla,String sql) throws SQLException, InstantiationException, IllegalAccessException{
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
T m = cla.newInstance();
m = qr.query(sql, new ResultSetHandler<T>(){ public T handle(ResultSet rs) throws SQLException {
ResultSetMetaData rm = rs.getMetaData();
T t = null;
try {
if(rs.next()){
t = cla.newInstance();
for(int i = 0; i<rm.getColumnCount(); i++){
String columnName = rm.getColumnName(i+1);
String str[] = columnName.split("_");
StringBuffer sb = new StringBuffer(str[0]);
for(int j = 1; j<str.length; j++){
str[j] = str[j].substring(0, 1).toUpperCase().concat(str[j].substring(1));
sb.append(str[j]);
}
String property = sb.toString();
Field field = cla.getDeclaredField(property);
field.setAccessible(true);
field.set(t, rs.getObject(columnName));
}
}else{
System.out.println("sql语句错误或对象不存在");
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return t;
} });
return m;
}

测试:

@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);
}

通过对DAO层的封装减少数据库操作的代码量

接下来是增删改操作,这个操作比较简单,不需要用到泛型和反射,只需要传入sql语句即可:

 public static boolean updateSql(String sql) throws SQLException{
boolean flag = false;
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
//执行修改操作
if(qr.update(sql)>0)
flag = true;
return flag;
}

还有预处理形式

 public static boolean updatePreparedSql(String sql,Object params[]) throws SQLException{
boolean flag = false;
QueryRunner qr = new QueryRunner(DBUtil.getDruid());
if(qr.update(sql,params)>0)
flag = true;
return flag;
}

还有批量处理形式

/**
* 通过预处理解决批量增删改操作
*
* @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;
}