最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【全球快播报】利用反射和代理简单模拟mybatis实现简单的CRUD

来源:博客园

利用反射接口做java数据库操作

今天突发奇想,好像一些基本的CRUD操作路数都是一样的,又想到mybatis中的操作,便想着简单的模拟一下。随便写写,就当练习反射了。

Dao接口类:

这里使用泛型,是为了更好的对数据进行处理


(资料图片)

public interface BaseDao {    // 获取所有信息    List getAll();    // 根据id查询信息    T getById(int id);    // 根据id修改信息    int updateById(T t);    // 根据id删除信息    int deleteById(int id);    // 插入数据    int insert(T t);    }

之前一直在犹豫,是否可以对接口创建代理类,后来查阅了一些资料,发现mybatis好像就是对接口的一些代理的处理。

使用JDK自带的代理接口InvocationHandler:

public class ProxyGen implements InvocationHandler { // 要代理的接口     private Class aClass;// 要处理的表名     private String tableName;// pojo的字节码文件     private Class objClass;// 完整的构造方法     public ProxyGen(Class interfaceClazz, String tableName, Class objClass) {         this.aClass = interfaceClazz;         this.tableName = tableName;         this.objClass = objClass;     }     @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{   ...... // 代码处理     }          // 获取代理类     public T getProxy() {         return (T) Proxy.newProxyInstance(aClass.getClassLoader(), new Class[]{aClass}, this);     }  }

下面展示一下利用反射做简单的CRUD:

先做一些简单的提前准备:

// 一些连接信息Connection connect = null;ResultSet rs = null;PreparedStatement ps = null;// 这时候通过反射拿到类的属性信息try {// 获取连接connect = SqlUtil.getConnect();} catch (Exception e) {throw new RuntimeException(e);}

把这些先声明出来,方便后续的管理和使用。

查询全部数据:

// 获取所有的学生信息if (method.getName().equalsIgnoreCase("getAll")) {    // 存储查询到的所有信息    List list = new ArrayList<>();    // 这里执行结果    ps = connect.prepareStatement("select * from " + tableName);    // 查询结果 进行封装    rs = ps.executeQuery();    // 按照顺序进行赋值    while (rs.next()) {        // 获取到所有的字段 进行反射赋值 必须确保有序 !        List fields = getClassFileds(objClass);        // 获取类对象        Object objClazz = objClass.getConstructor(null).newInstance(null);        // 赋值完毕        // 利用了反射出来的字符是有序的,这样保证了数据库的字段顺序和反射出来的字段顺序一致        for (int i = 0; i < fields.size(); i++) {            Object object = rs.getObject(i + 1);            fields.get(i).setAccessible(true);            fields.get(i).set(objClazz, object);        }        list.add( objClazz);    }// 关闭连接    SqlUtil.close(connect, ps, rs);    return list;}

根据id查询信息:

// 根据id查询信息 if (method.getName().equalsIgnoreCase("getById")) { // 先查看输入的参数是否获取到 System.out.println("args = " + Arrays.toString(args)); // 获取执行结果 ps = connect.prepareStatement("select * from " + tableName + " where id = " + args[0]); // 获取执行结果 rs = ps.executeQuery(); // 获取类对象信息 Object obj = objClass.getConstructor(null).newInstance(); // 获取POJO类的字段信息 List fileds = getClassFileds(objClass); while (rs.next()) { // 循环赋值 for (int i = 0; i < fileds.size(); i++) { // 因为字段是私有的 所以需要加上这一步 fileds.get(i).setAccessible(true); // 给字段赋值 fileds.get(i).set(obj, rs.getObject(i + 1)); } } // 释放资源 SqlUtil.close(connect, ps, rs); // 返回对象 return obj; }   /**  * 获取类反射字段  *  * @param objClass  * @return  */ private List getClassFileds(Class objClass) { ArrayList list = new ArrayList<>(); // 获取当前类的所有的字段 Field[] fields = objClass.getDeclaredFields(); for (Field field : fields) { list.add(field); } return list; }

根据Id修改信息:

既然是反射,那就得把数据写活,如果直接用pojo类的字段和属性,那不是写死了?

// 根据id修改信息 /**  * 这个比较特殊 传入的对象是一个student对象  */ if (method.getName().equalsIgnoreCase("updateById")) { // 拿到传输过来的对象 Object obj = args[0]; // 做一个自适应 如果值为null就不修改 Field[] fields = obj.getClass().getDeclaredFields(); // 拼接字符串 StringBuilder builder = new StringBuilder(); builder.append("update ").append(tableName).append(" ").append("set "); // 循环获取值 for (Field field : fields) { field.setAccessible(true); Object o = field.get(obj); if (o != null && !field.getName().equalsIgnoreCase("id")) { // 这里需要注意 如果对象为时间 需要转换一下 if (o instanceof Date) { o = String.format("%tF", (Date) o); } // 继续拼接              builder                    .append(field.getName())                    .append("=")                    .append(""")                    .append(o)                    .append(""")                    .append(","); } } // 拼接sql 如果拼接完最后一个字符为[,],需要去掉 String sql = builder.toString().endsWith(",") ? builder.deleteCharAt(builder.length() - 1).toString() : builder.toString(); // 主键id单独 处理 for (Field field : fields) { field.setAccessible(true); Object o = field.get(obj); if (field.getName().equalsIgnoreCase("id") && o != null) { sql += " where id = "" + o + """; } } System.out.println("sql = " + sql); // 执行对象 ps = connect.prepareStatement(sql); // 获取执行结果 int i = ps.executeUpdate(); SqlUtil.close(connect, ps, rs); return i;  }

根据id修改对象:

/**  * 根据id删除对象  */ if (method.getName().equalsIgnoreCase("deleteById")) {     // 获取参数 Integer arg = (Integer) args[0];     // 数据判断 避免空指针异常 if (arg != null) {         // 直接拼接删除sql语句 String sql = "delete from  " + tableName + " where id = " + arg; System.out.println("sql = " + sql); ps = connect.prepareStatement(sql); int i = ps.executeUpdate(); SqlUtil.close(connect, ps, rs); return i; } else { return 0; } }

插入数据:

// 插入数据 if (method.getName().equalsIgnoreCase("insert")) { // 传入的对象 Object obj = args[0]; // 根据传入的对象进行拼接sql Field[] fields = obj.getClass().getDeclaredFields(); // 拼接字符串 StringBuilder builder = new StringBuilder(); builder.append("insert into ").append(tableName).append(" ").append(" set "); for (Field field : fields) { field.setAccessible(true); Object o = field.get(obj); if (o != null) { // 这里需要注意 如果对象为时间 需要转换一下 if (o instanceof Date) { o = String.format("%tF", (Date) o); } builder.append(field.getName()).append("="").append(o).append("","); } } // 拼接sql 如果拼接完最后一个字符为[,],需要去掉 String sql = builder.toString().endsWith(",") ? builder.deleteCharAt(builder.length() - 1).toString() : builder.toString(); ps = connect.prepareStatement(sql); int i = ps.executeUpdate(); SqlUtil.close(connect, ps, rs); return i; }

简单测试了一下,还不错。

关键词: 所有信息 释放资源 进行处理