26. Hibernate 如何自动生成 SQL 语句
1. 前言
本节和大家一起聊聊 Hibernate 是如何自动生成 SQL 语句的。通过本节的学习,你将了解到:
- 反射在框架中的重要性;
- 元数据描述对 Hibernate 的重要性。
2. 理想状态
Hibernate 是全自动的 JDBC 框架,能自动构建 SQL 语句、能自动封装数据。
做为开发者,不能在使用的便利性中迷失自己,应该要学会多思考:Hibernate 是如何自动构建 SQL 语句的?
答案本身很简单:使用反射机制。
先来一个最理想化的构建实例:假设实体类名和表名相同、实体类中的属性和表中的字段命名相同。
编写自己的 Session 类:
public class MySession<T> {public T get(Class clz,Serializable id) { String sql=createSql(clz,id);//其它操作…… return null;}private String createSql(Class clz, Serializable id) { return null;}
}
get()方法接受 2 个参数,这 2 个参数便是构建 SQL 的核心。传递给内部的 createSql()方法用来进行 SQL 语句构造。
关注 createSql() 方法中的代码:
(1)声明变量。
// SQL 查询模板String sql = "select {0} from {1} where {2}= {3}";// 表名String tableName = null;// 字段列表StringBuffer selFields = new StringBuffer();// 主键字段String keyField = null;
(2)看来就是要为 SQL 查询模板中的占位符找到具体值。因为类名和表名相同,所以表名很容易找到。
// 类名就是表名tableName = clz.getSimpleName();
(3)因为属性名与表中的字段名相同,所以表的字段信息也很容易找到。
// 属性名就是查询的字段名,找到属性等于找到字段信息Field[] fields = clz.getDeclaredFields();
(4)这里有一个较麻烦的地方,怎么找到主键字段,这里假设第一个属性对应的是主键字段。
Field[] fields = clz.getDeclaredFields();for (int i = 0; i < fields.length; i++) {if (i == 0)keyField = fields[i].getName();selFields.append(fields[i].getName()).append(",");}// 删除最后一个,selFields.deleteCharAt(selFields.length() - 1);
(5)最后构建 SQL 。
sql = MessageFormat.format(sql, new Object[] {selFields,tableName,keyField,id});
测试输出大家自己去完成。
3. 非理想状态
前面假设了一种特别理想的状态。但是,现实总比理想残酷。
很多情况下,表名与类名、属性名和字段名都不同名,主键字段对应的属性也不一定放在第一个。
这种情形下,又如何构建 SQL 。此时,注解就起到了作用。大家还记得常用的注解吗?
- @Table;
- @Id;
- @Column。
有了这 3 个注解,查找表名、字段信息、主键字段就不需要再靠强制性的代码规范了。
重构 createSql() 方法中的代码。
本质上没有发生改变,还是为 SQL 查询模板中的占位符找到所有具体值。
(1)找到表名。其本思路是,如果有 @Table 注解,表名就是注解提供的名字,如果没有注解,则表名与类名相同;
// 查找类上面是否有 @Table 注解Table tableAnnotaion= (Table) clz.getAnnotation(Table.class);if(tableAnnotaion==null) //则认为类名与表名相同tableName = clz.getSimpleName();else //表名为注解中提供的值tableName=tableAnnotaion.name();
(2)找到表的所有字段信息。为了简化代码,假设 @Id 或 @Column 注解直接标注在属性上面。即使标注在 get()方法上面也不难;
// 属性信息Field[] fields = clz.getDeclaredFields();//是否存在 @Id 注解boolean ishasIdAnnotation = false;Id idAnnotation=null;Column columnAnnotation = null;String fieldName = null;for (Field field : fields) {// @Id 注解idAnnotation = field.getAnnotation(Id.class);// @ Column 注解columnAnnotation = field.getAnnotation(Column.class);if (idAnnotation != null) {keyField = field.getName();ishasIdAnnotation = true;}if (columnAnnotation == null)// 有 @Column 注解则从注解中取值fieldName = field.getName();else//没有 @Column 注解则和属性表相同fieldName = columnAnnotation.name();selFields.append(fieldName).append(",");}if (!ishasIdAnnotation) {throw new Exception("@Id 注解是必须的!");}// 删除最后一个,selFields.deleteCharAt(selFields.length() - 1);
(3)构建 SQL 语句。
sql = MessageFormat.format(sql, new Object[] { selFields, tableName, keyField, id });
测试 createSql()方法,在控制台可看到通过反射自动构建的 SQL 语句:
select stuId,stuName,stuSex,stuPassword from student where stuId= 1
测试结果需要以你自己的实体类和表做参考。
4. 小结
本节给出了 2 种情形下构建 SQL 语句的实现。
一种对编码规范要求非常严格,因为编码规范有很多人为因素,很难保证类结构和表结构如同镜像,不出现差异性。显然,在这种严格的编码规范下,构建 SQL 的性能消耗是最低的,所以,一入职场,第一堂课就是培训编码规范性。
第二种情形应该是一种常态,所以需要使用注解的方式标识差异性,当然,反射时付出的性能代价会增加。
本节没有讨论构建多表查询的实现,有了这些基础,相信都将不会很难。
相关文章:
26. Hibernate 如何自动生成 SQL 语句
1. 前言 本节和大家一起聊聊 Hibernate 是如何自动生成 SQL 语句的。通过本节的学习,你将了解到: 反射在框架中的重要性;元数据描述对 Hibernate 的重要性。 2. 理想状态 Hibernate 是全自动的 JDBC 框架,能自动构建 SQL 语句、…...
预言机(Oracle machine)
预言机(Oracle machine)是一个在多个领域中有不同应用和解释的概念。以下是从不同角度对预言机的详细解析: 一、计算复杂度理论与可计算性理论中的预言机 在计算复杂度理论与可计算性理论中,预言机是一种抽象电脑,用…...
55、PHP实现插入排序、二分查找
题目: PHP实现插入排序 描述: 思路:选择一个带插入的元素(假设从第一个开始),分别和已经插入有顺序的元素比较,如果要插入元素比比较元素小,则位置交换 function insertSort($arr){if(!is_array($arr)) return false;//外层循环插入次数for($i1;$i<…...
[Git][分支设计规范]详细讲解
目录 0.概览1.master分支2.release分支3.develop分支4.feature分支5.hotfix分支 0.概览 以下是常用的分支和环境的搭配,可视情况而定不同的策略 分支名称适用环境master主分支生产环境release预发布分支预发布/测试环境develop开发分支开发环境feature需求开发分支本…...
c#中winfrom需要了解的
如何用代码实现label1的字体大小 方法1:在设计视图中设置 打开你的Windows Forms项目。 在设计视图中,选中你想要更改字体大小的Label控件。 在属性窗口中,找到Font属性,点击旁边的省略号(...)。 在弹出的字体对话框中&#x…...
操作系统03:调度算法和文件系统
文章目录 调度算法进程调度算法先来先服务调度算法最短作业优先调度算法高响应比优先调度算法时间片轮转调度算法最高优先级调度算法 内存页面置换算法最佳页面置换算法(OPT)先进先出置换算法(FIFO)最近最久未使用的置换算法&…...
大量中国高清地图,必须收藏!!
1、中国人口密度 2、中国干湿区 3、中国温度带和干湿状况 4、中国气温分布 5、中国高陆状况 6、国家级高新技术产业开发区 7、中国工业布局的变化 8、中国旱灾 9、中国常年河与时令河 10、中国科斯塔地貌分布图 11、中国泥石流、滑坡崩塌灾害分布 12、中国森林和主要牧区分布图…...
无线领夹麦克风哪个品牌好,2024年收音麦哪个品牌好一点
在自媒体的浪潮中,内容创作者对于高质量音频的需求日益增长,这直接推动了无线领夹麦克风的兴起。过去,创作者们可能更倾向于使用传统的有线麦克风,但随着技术的进步和市场的变化,无线领夹麦克风以其便携性和灵活性的优…...
如何解决.NET8 类库Debug时,Debug文件夹中不包含Packages中引入的文件
最近在开发中使用了.NET8 Razor类库项目,但是惊讶的发现Debug时,Debug文件夹中不包含Packages中引入的文件,本以为是非常小的问题,但是被困住了竟然足足4个小时。 其实它也本就是个非常非常小的问题…… 只需引入<CopyLocalL…...
域名安全详解
域名安全是网络安全的重要组成部分,涉及多个方面。以下是域名安全的详细介绍: 1. 域名劫持防护 域名劫持是指攻击者通过各种手段,将用户访问的域名解析到非法IP地址上。 防护措施: 使用DNSSEC(域名系统安全扩展)定期监控域名解析记录选择可靠的域名注册商和DNS服务提供…...
使用gstreamer命令行解析RTSP流
1、解析成图片: gst-launch-1.0 rtspsrc locationrtsp://xxxx protocolstcp ! rtph264depay ! h264parse ! queue ! avdec_h264 ! videoconvert ! videorate ! videoscale ! videoconvert ! capsfilter capsvideo/x-raw,formatI420,width640,height480,framerate30…...
如何基于离线包中“事件热点”进行二次开发
720漫游支持基于作品离线包中的自定义按钮/热点-事件进行二次开发来实现与自己业务相关的扩展功能。 开发者可以基于离线包二次开发自定义设置点击热点图标需要执行什么操作?比如打开实时监控画面弹窗,调用自己后台的数据并弹窗显示等。 操作流程&…...
使用继电器实现门电路(1)常用门电路的简化实现
非门INC 常闭x1 反向输入信号 与门AND 常开x1 当A和B都为1时,O才为1,否则O为0。 或门OR 常开x1 当A和B中任意一个为1时,O为1,只有当A和B都为0时,O才为0。 或非门NOR 当A和B中任意一个为1时,O为0&…...
程序员常用单词分类
程序员在编程、软件开发、系统维护等工作中,会频繁使用到一系列特定的单词和术语。这些单词可以根据其功能、用途或所属领域进行分类。以下是一些常见的分类及其示例单词: 1. 数据类型与变量 数据类型:整型(Integer)…...
c语言11天笔记
函数的概述 函数:实现一定功能的,独立的代码模块。我们的函数一定是先定义,后使用。 使用函数的优势: 1. 我们可以通过函数提供功能给别人使用。当然我们也可以使用别人提供的函数,减少代码量。 2. 借助函数可以减…...
【C++刷题】优选算法——贪心第三辑
坏了的计算器 int brokenCalc(int startValue, int target) {int step 0;while (target > startValue) {if (target % 2 0) target / 2;else target 1;step;}return step startValue - target; }合并区间 区间问题,先排序 vector<vector<int>>…...
9.2 grafana 上导入模板看图并讲解告警
本节重点介绍 : 添加到prometheus采集配置中grafana 上导入process-exporter dashboard重点指标讲解 添加到prometheus采集配置中 - job_name: process-exporterhonor_timestamps: truescrape_interval: 15sscrape_timeout: 10smetrics_path: /metricsscheme: httpstatic_con…...
python实现自动回复消息
本文使用创作助手。 下面是一个使用uiautomation库实现自动回复QQ消息的示例代码: import time import uiautomation as autodef auto_reply():# 打开QQauto.uiautomationhelper.ShellExecute(r"C:\Program Files (x86)\Tencent\QQ\Bin\QQScLauncher.exe&quo…...
Mysql 脚本转换为drawio ER 脚本
Navicat 导出数据库脚本 通过代码转换脚本 import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** SQL 脚本转换为 drawio ER 脚本*/ pu…...
基于babylonjs的小游戏 跳一跳
源码地址...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...
