首页 > 其他分享 >27. Hibernate 自动进行数据封装

27. Hibernate 自动进行数据封装

时间:2024-08-13 14:25:33浏览次数:7  
标签:27 封装 rs entity field Hibernate clz null 属性

1. 前言

Hibernate 可以构建各种复杂的 SQL 语句,但其本质都是反射机制结合映射关系完成的。

框架也仅是一款程序产品,人为编写的产物。要相信,只要你愿意,你完全可以实现自己的 JDBC 框架。

本节课和大家继续聊聊 Hibernate 是如何自动封装数据的。

2. 理想状态

程序中的数据通过 SQL 语句传递给数据库,从 IO 流的角度上理解是数据的输出。

把数据库中的数据封装成程序能识别、使用的类型,这个过程叫数据库封装。从 IO 流的角度上讲是数据的输入。

数据封装的实现还是利用反射机制。

数据封装的思路也简单。

表结构对应类结构,一行记录或说一个实体对应一个对象,字段对应属性。还是同样的配方。

即将编写实例之前,先做一个理想化的假设:

  • 表名和类名相同;
  • 表中的字段名和类中的属性名相同;
  • 实体类中没有特别复杂的数据类型。

理想状态设定便于大家由浅入深理解实现过程。

真实项目中,很难达到理想化状态 。因为 JAVA 程序和关系型数据库的命名规范有差异性,不管谁迁就谁,都会让彼此难受。

在上一节课的自定义 Session 对象中添加一个封装方法:

public class MySession<T> {
public T get(Class<T> clz, Serializable id) throws Exception {
	String sql = createSql_(clz, id);
	// JDBC 常规操作…… 得到结果集
	ResultSet rs=this.getRs(sql);
	//数据封装
	T entity= this.wrap(clz, rs);	
	return entity;
}
/**
*构建 SQL ,具体代码参考本系列的《Hibernate 自动生成SQL语句》 
*/
private String createSql(Class<T> clz, Serializable id) {
    return null;
}
/**
*得到结果集,此方法就是常规的 JDBC 操作
*/
private ResultSet getRs(String sql) {
    return  null;
}
/**
*数据封装
*/
private T  wrap(Class<T> clz,ResultSet rs) throws InstantiationException, IllegalAccessException {
	return null;
}
}

关注 wrap()方法即可,直接让代码说话:

private T  wrap(Class<T> clz,ResultSet rs) throws InstantiationException, IllegalAccessException {
	// 通过反射创建对象
	T entity = clz.newInstance();
	String attName = null;
	Object value = null;
	// 检查结果集中是否存在数据
	if (rs.next()) {
		// 属性信息
		Field[] fields = clz.getDeclaredFields();
		for (Field field : fields) {
			// 表的字段名即类的属性名
			attName = field.getName();
			// 从结果集获取值
			value = rs.getObject(attName);
            //允许直接访问私有属性
			field.setAccessible(true);
            //数据封装
			field.set(entity, value);
		}
	}
	return entity;
}

上面代码没有进行类型转换相关操作,依靠 JAVA 自动类型转换完成,对于常用的基本类型,不会出多大问题。但对于较复杂的数据类型,需要编码进行强制类型转换。

下面这 2 行代码,通过打破私有属性的壁垒,直接给属性赋值。只适合用于验证、测试环境下。

field.setAccessible(true);
field.set(entity, value);

测试一下代码:

Student stu = new MySession<Student>().get(Student.class, new Integer(1));
System.out.println(stu);

在一切理想的状态下,一个简易的 JDBC 框架就开始工作了。

虽然它很薄弱,且不堪重负,但是,它是黑暗中的一道光,能指导你认识框架本质。

3. 非理想状态

再来一个非理想状态下的实现:

  • 类名与表名不同名;
  • 类中的属性名与表中的字段名有不同的命名;

整体思想和上面代码没有区别,通过属性名找到字段名,因为属性名和字段名不相同,所以需要通过属性上面的注解信息得到字段名。

让代码自己说话:

private T wrap_(Class<T> clz, ResultSet rs) throws InstantiationException, IllegalAccessException, SQLException,NoSuchMethodException, SecurityException, IllegalArgumentException,InvocationTargetException {
	// 使用反射创建对象
	T entity = clz.newInstance();
	// 属性名
	String attName = null;
	// 列名
	String columnName = null;
	Object value = null;
	Column columnAnnotaiton = null;
	// 检查结果集中是否存在数据
	if (rs.next()) {
		// 属性信息
		Field[] fields = clz.getDeclaredFields();
		for (Field field : fields) {
			// 属性名
			attName = field.getName();
			// 查看属性上面的注解
			columnAnnotaiton = field.getAnnotation(Column.class);
			if (columnAnnotaiton != null) {
				columnName = columnAnnotaiton.name();
			} else {
				columnName = attName;
			}
			// 从结果集中获取值
			value = rs.getObject(columnName);
			// 属性的 set 方法名
			String setMethodName = "set" + attName.substring(0, 1).toUpperCase() + attName.substring(1);
			// 属性的 set 方法
			Method setMethod = clz.getDeclaredMethod(setMethodName, new Class[] { field.getType() });
			setMethod.invoke(entity, new Object[] { value });
			}
		}
		return entity;
	}

上面代码一样没有考虑复杂类型存在情况。

4. 小结

本节课程和大家聊了聊 Hibernate 是如何自动实现数据封装的,从实现原理上讲,还是比较容易理解的。

但是,真实环境的需求总是千变万化的,理想只存于理想中。

Hibernate 的实现和我们实现的最大区别在于,它总是能适应不同的需求,要适应不同的需求,无论是代码的设计还是编码都会有难度。

但是,千里之行,始于脚下,一步一步,终能看透所有的本质。

标签:27,封装,rs,entity,field,Hibernate,clz,null,属性
From: https://blog.csdn.net/u014316335/article/details/141136433

相关文章

  • 基于Python训练完成的机器学习模型如何封装成桌面应用
    有时候需要将训练完成的模型封装成桌面应用,本文描述封装成基于Python的桌面应用程序的方法。模型封装是指将模型及其预处理和后处理步骤打包在一起,形成一个独立的服务单元。确保机器学习模型已经训练完成并且能够在本地环境中正确运行。Python有多种GUI库可供选择,如Tkinter、......
  • Java封装 小白版
    封装使用对象的方法将对象的变量和方法保护起来,就称为封装。外界只能通过对象的接口(方法)访问对象的服务。封装就是隐藏对象的属性和实现细节,仅提供公共访问方式来让外界访问快捷键:Alt+insert——>GetterandSetter封装的好处隐藏类的实现细节只能通过规定方法访问数据方......
  • vue 多时间段范围选择及回显 组件封装
     <template><divclass="flex-col"><ul><liv-for="(item,index)inclassActiveList":key="index"><!--@click="toggleSelection(item.id)"-->......
  • Day27 贪心算法part1
    任务455.分发饼干假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子i,都有一个胃口值g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j,都有一个尺寸s[j]。如果s[j]>=g[i],我们可以将这个饼干j分配给孩子i,这......
  • 代码随想录day27 || 455 分饼干,376 摆动序列,53 最大子序列和
    分饼干funcfindContentChildren(g[]int,s[]int)int{ //第一思路,双指针暴力解法 varcountint varused2=make([]bool,len(s)) g=quicksort(g) s=quicksort(s) for_,child:=rangeg{ foridx,cookie:=ranges{ if!used2[idx]&&cookie>=......
  • P1272 重建道路
    题目点击查看题目题目描述一场可怕的地震后,人们用\(N\)个牲口棚(编号\(1\simN\))重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是唯一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的......
  • JS【详解】数据类型检测(含获取任意数据的数据类型的函数封装、typeof、检测是否为 nul
    【函数封装】获取任意数据的数据类型/***获取任意数据的数据类型**@paramx变量*@returns返回变量的类型名称(小写字母)*/functiongetType(x){//获取目标数据的私有属性[[Class]]的值constoriginType=Object.prototype.toString.call(x);//......
  • 027.Vue3入门,父页面接收子页面传过来的事件和参数
    1、App.vue代码:<template><Father/></template><scriptsetup>importFatherfrom'./view/Father.vue'</script><style></style>2、Father.vue代码:<template><h3>父页面</h3><Chi......
  • AJAX - 利用XML和Promise封装简易版axios,了解axios底层原理
     AJAX原理-XMLHttpRequest定义:XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest 在 AJAX 编程中被大量使用。关系:axios内部采用......
  • Java工具类封装微服务间HTTP通信
    在微服务架构中,服务之间通常通过HTTP协议进行通信。为了简化这一过程,我们可以创建一些工具类来封装HTTP请求的发送逻辑。本篇文章将介绍如何使用Java来创建这样的工具类,并分别演示使用ApacheHttpClient和SpringFramework中的RestTemplate来发送HTTPGET请求的方法。1.引言......