两种封装执行sql的方式

方式一:技术手段《泛型+反射》,核心区别:赋值流程自己(在公共方法内)实现

方式二:设计手段,抽象,核心区别:赋值流程自己,谁调用,谁实现

package day06;
/*
crud 增删改查

*/

import day05.jdbc.MysqlUtil;
import day05.jdbc.TbUser;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DaoDemo01 {
public static void main(String[] args) throws Exception {
String sql ="select * from auth_group";
List<TbUser> tbUsers = testDao(sql, null, TbUser.class);
System.out.println(tbUsers);


// RowMapper思想
// 区别:反射的方法,实现对象的赋值,在我们写的统一方法里,统一处理供别人调用
// 区别:RowMapper方法,谁调用我们,谁就要实现接口里面对象赋值的方法(匿名内部类)
// 抽象:接口+抽象类
// 第三个参数,传rowMapper接口,
// rowMapper接口,这里使用匿名内部类
// new RowMapper<TbUser>() {....});这里是一行代码(这里用的匿名内部类)
List<TbUser> tbUsers1 = testRowMapper(sql, null, new RowMapper<TbUser>() {

// 重写map
@Override
public TbUser map(ResultSet rs) throws SQLException {
TbUser tbUser = new TbUser();
// 给tbUser赋值
tbUser.setId(rs.getLong(1));
tbUser.setName(rs.getString(2));
return tbUser;
}
});
System.out.println("tbUsers1 = " + tbUsers1);

}


/**
* 根据Sql语句,获取对象集合 《泛型+反射》,技术手段
* @param sql
* @param params sql语句的参数,参数的顺序需要使用方自己控制
* @param cls 对象的class
* @param <T> 对象的类型
* @return List<T>
* @throws Exception
*/
public static <T> List<T> testDao(String sql,List<Object> params,Class<T> cls) throws Exception {
// 静态方法的泛型
// 传参,sql和sql里面的变量
//Class<T> cls,拿到一个类的Class,通过反射然后构建对象
//拿到对象的属性字段,然后给属性设置值

//1、建立连接
Connection conn = MysqlUtil.getConn();
//2、预编译
PreparedStatement ps = conn.prepareStatement(sql);
if (params!=null){
// 给sql语句设置参数,参数的顺序使用方自己控制
for (int i=0;i< params.size();i++){
// jdbc 参数从1开始数,所以是i+1
ps.setObject(i+1,params.get(i));
}
}

// 3、运行sql,得到结果集
ResultSet rs = ps.executeQuery();
// 集合
List<T> list =new ArrayList<>();
while (rs.next()){
// 通过class,利用反射,构建一个T对象
// 注意,这个T类,一定要有无参构造器
T t = cls.newInstance();
// 通过反射,得到T这个类所有的属性/字段
Field[] fields = cls.getDeclaredFields();
// 遍历属性,给t的属性赋值
for (Field field:fields){
// 得到属性field的名字,根据field的名字作为列名,在结果集rs中取对应的值
// 注意:
String fieldName =field.getName();//属性/字段的名称
field.setAccessible(true);//设置字段可访问的权限

//在结果集中,通过列名fileName,来或者对应的值
// 我们不知道具体是什么类,所以我们用Object
// 根据列名在结果集中取值,使用属性名作为列名
// 注意:类T的属性名要与数据库列的字段名称保持一致
Object object = rs.getObject(fieldName);

//给对象的当前属性设置值
//这里涉及到3个数据,field.set(t,object),里面第一个参数传的是实例,
// 第二个参数是给当前的属性设置的值
// 当前是什么属性?我们就在遍历for (Field field:fields)属性的循环里,取的当前的属性
field.set(t,object);

}
// 给存放结果集的集合,添加对象
list.add(t);

}
MysqlUtil.close(conn);//关闭数据库连接
return list;
}
//---------------------rowMapper---------------
//定义一个接口
// 泛型 T
interface RowMapper<T>{
T map(ResultSet rs) throws SQLException;

}

/**
* 《泛型+抽象》设计手段,抽象的概念,封装
* @param sql
* @param params
* @param rowMapper
* @param <T>
* @return
* @throws SQLException
*/
// 泛型
// 这里不用class反射,用RowMapper<T>接口
public static <T> List<T> testRowMapper(String sql,List<Object> params,RowMapper<T> rowMapper) throws SQLException{
// 建立连接
Connection conn = MysqlUtil.getConn();
// 预编译
PreparedStatement ps = conn.prepareStatement(sql);
if (params!=null){
// 给sql语句设置参数,参数的顺序使用方自己控制
for (int i=0;i< params.size();i++){
// jdbc 参数从1开始数,所以是i+1
ps.setObject(i+1,params.get(i));
}
}

//结果集
ResultSet rs = ps.executeQuery();
// 创建一个集合,来接收执行sql后的结果集
List<T> list = new ArrayList<>();
while (rs.next()){
// rowMapper的map方法,传rs,得到一个t
T t = rowMapper.map(rs);
list.add(t);
}
return list;

}
}