首页 > 其他分享 >利用反射和代理简单模拟mybatis实现简单的CRUD

利用反射和代理简单模拟mybatis实现简单的CRUD

时间:2023-02-13 20:46:14浏览次数:61  
标签:ps builder sql CRUD field 简单 mybatis id append

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

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

Dao接口类:

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

public interface BaseDao<T> {

    // 获取所有信息
    List<T> 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<T> implements InvocationHandler {
	 // 要代理的接口
     private Class<T> aClass;
	// 要处理的表名
     private String tableName;
	// pojo的字节码文件
     private Class objClass;
	// 完整的构造方法
     public ProxyGen(Class<T> 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<Student> list = new ArrayList<>();
    // 这里执行结果
    ps = connect.prepareStatement("select * from " + tableName);
    // 查询结果 进行封装
    rs = ps.executeQuery();
    // 按照顺序进行赋值
    while (rs.next()) {
        // 获取到所有的字段 进行反射赋值 必须确保有序 !
        List<Field> 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((Student) 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<Field> 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<Field> getClassFileds(Class objClass) {
	 ArrayList<Field> 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;

 }

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

image-20230213202936574

标签:ps,builder,sql,CRUD,field,简单,mybatis,id,append
From: https://www.cnblogs.com/beishanqingyun/p/17117730.html

相关文章

  • js 0.1+0.2 !== 0.3 简单解决方案
    exportconstround=number=>{constgetFloat=number.toString().split(".");if(getFloat.length===1){returnnumber;}constfloatLength=getFloa......
  • 有效的字母异位词(力扣简单哈希表题)
    题目:给定两个字符串*s*和*t*,编写一个函数来判断*t*是否是*s*的字母异位词。注意:若*s*和*t*中每个字符出现的次数都相同,则称*s*和*t*互为字母异位词。思......
  • 密码学简单数论笔记(2):最大公约数、扩展欧几里得算法和最小公倍数
      参考资料:1.https://www.bilibili.com/video/BV1x3411s7Sy/?spm_id_from=333.788&vd_source=e66dd25b0246f28e772d75f11c80f03c2.http://t.csdn.cn/diQ272.余红兵:《......
  • 简单解释 什么是Redux
    我已经有一段时间没有写任何东西了。我收到了很多关于在Redux上创建教程的消息!所以就在这里。我花了很多天时间使本教程更加简单易懂。现在让我们开始吧^_^在进入什么是R......
  • 如何编写一个简单的 CLI 应用程序来下载、转换视频并将其保存为音频
    您是否一直想知道如何创建一个非常简单的CLI应用程序,让您可以从YouTube下载视频,将它们转换为音频,然后将它们保存到计算机上的指定文件夹中?在这篇文章中,我想解释一种在P......
  • RabbitMQ简单消息发送与接收
    RabbitMQ简单消息发送与接收​​1、前言​​​​2、简单消息发送与接收实战​​​​2.1引入依赖​​​​2.2消息生产者​​​​2.3消息消费者​​​​2.4测试​​1、前......
  • MyBatisPlus常用注解
    MyBatisPlus常用注解@TableName:自定义表名给User实体类添加注解aplication.yml中添加mp的配置#配置mp的日志mybatis-plus:configuration:log-impl:org.apache.ibati......
  • Mybatis缓存
    什么是MyBatis中的缓存MyBatis中的缓存就是说MyBatis在执行一次SQL查询或者SQL更新之后,这条SQL语句并不会消失,而是被MyBatis缓存起来,当再次执行相同SQL语句的时候,就会......
  • python画图的简单案例
    #导包frompyecharts.chartsimportLinefrompyecharts.optionsimportTitleOpts,ToolboxOpts,LegendOpts,VisualMapOpts#创建一个折线图像对象,即创建一个空的坐标系line......
  • mybatis基于注解的多对多关联操作
    文章目录​​一、前言​​​​二、实体类:​​​​1、角色类RoleInfo​​​​2、权限类:ModuleInfo​​​​3、中间表ModuleRole​​​​三、多对多操作​​​​1、向中间表......