厉害哦!从未见过如此简单粗暴的Hibernate教程
liebian365 2024-10-23 13:52 25 浏览 0 评论
原文作者:肥朝
内容大纲
引题
对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的规范,简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中。
面向对象概念面向关系概念类表对象表的行(记录)属性表的列(字段)
ORM框架在前后端领域都能看到它的影子,比如Android的greenDAO、iOS的coreData、Node.js的mongoose,这里主要讲解Java中Hibernate我们比较容易忽略和重要的点。
save和get的执行流程
save和get
save:
- 根据对象找到user类(user.getClass)和对应的映射文件User.hbm.xml,并解析出表名t_user
- 使用内省机制操作user对象,获取其中的属性:id/name
- 解析映射文件,找到属性对应的列名
- 根据主键生成策略,如果是native,此时主键就不出现在SQL语句中,如当前的SQL语句为:insert into t_user(uname) values (?)其中?就对应user.getXxx()方法
get:
- 根据对象找到user类(user.getClass)和对应的映射文件User.hbm.xml,并解析出表名t_user
- 解析映射文件,找到<id>元素对应的列名uid,SQL就拼接成功了
- 处理结果集,把一条数据封装成User对象
- 创建User对象
- 根据列名找到对应的属性名,调用user.setXxx()后返回对象
get和load方法的区别
先看这段简单的测试代码:
- get会立即发送select语句,load不会立刻发送,当使用到该对象的非OID属性时才会发送,延迟加载
- load方法返回的对象永远不为null,即使在数据库中不存在,所以不能使用if-null的方式来判断,而get可以为null,因为load执行的时候没有发送select语句,所以他不知道数据库中有没有对应数据,所以索性返回一个不为null的对象,如果存在,则再把数据设置到对象中去,如果不存在,使用该对象时报错
- load方法会创建出代理对象,但是代理对象必须在session关闭之前创建出来,否则会报hibernate中最常见的错误,no session,解决办法为Hibernate.initialize(代理对象)
持久化对象的生命周期
为什么需要关注持久化对象的生命周期?那我们来回忆使用Hibernate中是否遇到的三个问题:
- 问题一:主键生成策略不同,save操作时发生INSERT语句的时机不同?
- native:在执行save方法的时候发送INSERT SQL
- increment:在提交事务的时候,才发送INSERT SQL
- 问题二:删除对象的时候,没有立刻发生DELETE语句,而是在提交事务的时候发送的。
- 问题三:为什么在事务环境下,通过get方法得到的对象,只要修改了属性值,会发生UPDATE语句。
那么SQL的执行时机和什么有关系呢?和对象的状态有关系。那持久化对象的状态有哪一些?怎么划分的?
划分的规则::
- 当前对象是否有OID(该对象在表中对应有一个id值)
- 对象是否被session所管理(对象是否在一级缓存中)
状态描述特点临时状态/瞬时态(transient)刚刚用new语句创建,没有被持久化,不处于session中没有oid,不在session当中持久化状态(persistent)已经被持久化,加入到session的缓存中有oid,在session当中游离状态(detached)/脱管态已经被持久化,但不处于session中有oid,不在session当中删除状态(removed)对象有关联的ID,并且在session管理下,但是已经计划被删除有oid,在session当中,最终的效果是被删除.
持久化对象的状态
对象状态的总结
session中的方法仅仅只是改变对象的状态,不负责发送SQL/默认情况下事务提交的时候发送SQL,那么之前是三个问题就可以迎刃而解了。
- 问题一解答:save方法仅仅是把临时状态的对象转换为持久化状态,本身不负责发送SQL。临时状态的对象没有OID,调用save方法之后,变成持久化状态,就必须有OID。 * native:表示数据库主键的自增长,只有发送SQL,才能获取主键,从而获取OID
- increment:先发送SELECT语句查询id(拥有了OID),不需要发送increment来获取OID
- 问题二解答:delete方法仅仅是改变对象的状态,本身不负责发送SQL。因此按照默认的方式,提交事务的时候发送SQL
- 问题三解答:通过get查询操作得到的对象处于持久化状态(有OID,存在于一级缓存中)。此时,修改了非IOD的属性值,发现一级缓存中的数据和快照区域的数据不同(脏数据),Hibernate就会做比较(一级缓存和快照区),发现不同,就发送UPDATE语句,做数据同步。session的flush方法,负责把一级缓存中的脏数据同步到数据库中去
二级缓存
要了解二级缓存,我们就必须知道一级缓存是什么。介绍一级缓存之前,我们先回顾一下Session。
session
- session对象,通过sessionFactory对象创建而来,包含了connection对象,封装了很多操作方法
- session不是线程安全的(使用局部变量),所以,session的最大生命周期:一个线程,在web应用当中,一个session的最大生命周期:request
- session中有一个缓存,称为一级缓存。存放当前工作单元加载的对象。在一个session的生命周期之内,连续拿相同类型,相同ID的对象,只需要发送一次SQL
原理如图:
一级缓存
虽然一级缓存可以提高性能,但是由于session的作用域有限,因此,提高的性能也是非常有限的,所以这就引出了二级缓存的概念:
二级缓存
- 在整个应用中,有且只需要一个sessionFactory对象即可
- 生命周期为整个应用的缓存(二级缓存是sessionFactory上的缓存,能提供整个应用中所有的session使用)
- 所有的get,load方法,总是先查一级缓存,再查二级缓存,如果都没有,在去数据库里面查询
若想了解Hibernate和Mybatis的缓存对比可以戳这里《Hibernate和Mybaitis缓存》(http://www.jianshu.com/p/fe4d82c8c97c)
事务并发问题
事务并发时,会产生两类丢失更新问题,如图:
- 第一类丢失更新:A事务撤销时,把已经提交的B事务的更新数据覆盖了。
第一类丢失更新问题
- 第二类丢失更新:A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。
第二类丢失更新问题
然而解决的办法有两个,一个称之为悲观锁,一个称之为乐观锁。
悲观锁(Pessimistic Lock):悲观地认为每次自己去拿数据的时候别人会修改数据,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。底层采用的就是SELECT ..... FOR UPDATE
悲观锁
乐观锁(Optimistic Lock):乐观地认为每次去拿数据的时候别人不会修改数据,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁
在Hibernate中使用乐观锁,推荐使用version方式:
最后,我自己是一名从事了多年开发的Java老程序员,辞职目前在做自己的Java私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的Java学习干货,可以送给每一位喜欢Java的小伙伴,想要获取的可以关注我的头条号并在后台私信我:01,即可免费获取。
相关推荐
- go语言也可以做gui,go-fltk让你做出c++级别的桌面应用
-
大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...
- 旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗
-
这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...
- codeblocks和VS2019下的fltk使用中文
-
在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...
- FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库
-
FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...
- 中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux
-
IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...
- Linux 5.13内核有望合并对苹果M1处理器支持的初步代码
-
预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...
- Ubuntu系统下COM口测试教程(ubuntu port)
-
1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...
- 湖北嵌入式软件工程师培训怎么选,让自己脱颖而出
-
很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...
- 新阁上位机开发---10年工程师的Modbus总结
-
前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...
- 创建你的第一个可运行的嵌入式Linux系统-5
-
@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...
- 如何在Linux下给zigbee CC2530实现上位机
-
0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...
- Python实现串口助手 - 03串口功能实现
-
串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...
- 为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口
-
UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...
- 同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理
-
串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...
- 嵌入式linux为什么可以通过PC上的串口去执行命令?
-
1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- go语言也可以做gui,go-fltk让你做出c++级别的桌面应用
- 旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗
- codeblocks和VS2019下的fltk使用中文
- FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库
- 中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux
- Linux 5.13内核有望合并对苹果M1处理器支持的初步代码
- Ubuntu系统下COM口测试教程(ubuntu port)
- 湖北嵌入式软件工程师培训怎么选,让自己脱颖而出
- 新阁上位机开发---10年工程师的Modbus总结
- 创建你的第一个可运行的嵌入式Linux系统-5
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)