百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

厉害哦!从未见过如此简单粗暴的Hibernate教程

yuyutoo 2024-10-12 01:38 10 浏览 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,即可免费获取。

相关推荐

Python操作Word文档神器:python-docx库从入门到精通

Python操作Word文档神器:python-docx库从入门到精通动动小手,点击关注...

Python 函数调用从入门到精通:超详细定义解析与实战指南 附案例

一、函数基础:定义与调用的核心逻辑定义:函数是将重复或相关的代码块封装成可复用的单元,通过函数名和参数实现特定功能。它是Python模块化编程的基础,能提高代码复用性和可读性。定义语法:...

等这么长时间Python背记手册终于来了,入门到精通(视频400集)

本文毫无套路!真诚分享!前言:无论是学习任何一门语言,基础知识一定要扎实,基础功非常的重要,找一个有丰富编程经验的老师或者师兄带着你会少走很多弯路,你的进步速度也会快很多,无论我们学习的目的是什么,...

图解Python编程:从入门到精通系列教程(附全套速查表)

引言本系列教程展开讲解Python编程语言,Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,它也是互联网最热门的编程语言之一。Python生态丰富,库(模块)极其丰富,这使...

Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够

本书是Python经典实例解析,采用基于实例的方法编写,每个实例都会解决具体的问题和难题。主要内容有:数字、字符串和元组,语句与语法,函数定义,列表、集、字典,用户输入和输出等内置数据结构,类和对象,...

Python函数全解析:从入门到精通,一文搞定!

1.为什么要用函数?函数的作用:封装代码,提高复用性,减少重复,提高可读性。...

Python中的单例模式:从入门到精通

Python中的单例模式:从入门到精通引言单例模式是一种常用的软件设计模式,它保证了一个类只有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁创建和销毁的对象,比如日志对象、线程池、缓存等...

【Python王者归来】手把手教你,Python从入门到精通!

用800个程序实例、5万行代码手把手教你,Python从入门到精通!...

Python从零基础入门到精通:一个月就够了

如果想从零基础到入门,能够全职学习(自学),那么一个月足够了。...

Python 从入门到精通:一个月就够了

要知道,一个月是一段很长的时间。如果每天坚持用6-7小时来做一件事,你会有意想不到的收获。作为初学者,第一个月的月目标应该是这样的:熟悉基本概念(变量,条件,列表,循环,函数)练习超过30个编...

Python零基础到精通,这8个入门技巧让你少走弯路,7天速通编程!

Python学习就像玩积木,从最基础的块开始,一步步搭建出复杂的作品。我记得刚开始学Python时也是一头雾水,走了不少弯路。现在回头看,其实掌握几个核心概念,就能快速入门这门编程语言。来聊聊怎么用最...

神仙级python入门教程(非常详细),从0到精通,从看这篇开始!

python入门虽然简单,很多新手依然卡在基础安装阶段,大部分教程对一些基础内容都是一带而过,好多新手朋友,对一些基础知识常常一知半解,需要在网上查询很久。...

Python类从入门到精通,一篇就够!

一、Python类是什么?大家在生活中应该都见过汽车吧,每一辆真实存在、能在路上跑的汽车,都可以看作是一个“对象”。那这些汽车是怎么生产出来的呢?其实,在生产之前,汽车公司都会先设计一个详细的蓝图...

学习Python从入门到精通:30天足够了,这才是python基础的天花板

当年2w买的全套python教程用不着了,现在送给有缘人,不要钱,一个月教你从入门到精通1、本套视频共487集,本套视频共分4季...

30天Python 入门到精通(3天学会python)

以下是一个为期30天的Python入门到精通学习课程,专为零基础新手设计。课程从基础语法开始,逐步深入到面向对象编程、数据处理,最后实现运行简单的大语言模型(如基于HuggingFace...

取消回复欢迎 发表评论: