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

Hibernate 自动进行数据封装

时间:2023-01-31 22:59:19浏览次数:47  
标签:Hibernate 封装 entity field 自动 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 的实现和我们实现的最大区别在于,它总是能适应不同的需求,要适应不同的需求,无论是代码的设计还是编码都会有难度。

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

标签:Hibernate,封装,entity,field,自动,clz,null,属性
From: https://www.cnblogs.com/10zhan/p/17081083.html

相关文章

  • 验证oracle创建唯一键后索引的自动生成
    文档课题:验证oracle创建唯一键后索引的自动生成.数据库:oracle11.2.0.41、原表数据HR@orcl150>DESCtest2;NameNull?Type---......
  • Docker部署Nacos自动停止运行
    1、现象使用docker部署的Nacos在运行一段时间后,就自动停止运行了。查看docker运行容器,nacos停止了2、解决因为是学生购买的轻量级服务器,所以配置很低,出现这种问题我默......
  • 家庭宽带IPV6使用方式,终端SLAAC,DHCPV6自动配置
    使用运营商分配的ipv6地址分几种情况1运营商只给一段ipv6(一般不会)2运营商分配一段供互联使用ipv6,另外给一段PD前缀对于第一种方式没有更好的办法,地址分配......
  • PHPMyWind支持Word自动导入
    ​ 项目需求可发布文章需求涉及到富文本编辑器经过查阅我选择了较为简便不需要后端支持可独立完成的tinymce框架官方文档也是相当完整虽然都是全英文但是有强大的......
  • App自动化测试|原生app元素定位方法
    ##元素定位方法介绍及应用Appium方法定位原生app元素通过appiuminspector工具,可以获取元素的相关信息;在appium中提供了一系列的元素定位API,通过在这些API中输入指定的元素......
  • App自动化测试|原生App元素定位方法(二)
    uiautomator方法定位原生app元素appium在android端是调用其底层的UIAutomator2自动化测试框架去驱动自动化,在定位元素的时候,可以借助UIAutomator2的语法来实现定位。在代码......
  • 接口自动化测试|Requests库的安装与介绍
    Requests:Requests模块简介与安装Requests模块简介在python的标准库中,虽然提供了urllib,utllib2,httplib,但是做接口测试,requests使用更加方便快捷,正如官方说的,“让HTTP服务人......
  • PHPMyWind支持Word自动上传
    ​ 当前功能基于PHP,其它语言流程大致相同 1.新增上传wordjson配置在ueditor\php\config.json中新增如下配置:     /* 上传word配置 */    "wordAction......
  • AC 自动机
    AC自动机AC自动机是以Trie的结构为基础,结合KMP的思想建立的。简要步骤将所有的模式串构成一棵Trie。对Trie树上所有的结点构造失配指针。然后就可以利用......
  • 使用vant、promise封装回调、全局状态共享、分包
    应用的生命周期onLaunch:启动应用时调用onShow:显示时调用,可能调用多次onHide:隐藏时调用(进入到后台),可能调用多次onError:整个应用如果某个部分有报错就调用页面的......