频道栏目
首页 > 资讯 > 云计算 > 正文

云计算Hibernate工作原理解析

18-05-07        来源:[db:作者]  
收藏   我要投稿

Hibernate工作原理

这里写图片描述

1. hibernate工作原理简介

1.1 hibernate工作流程

通过上面的体系结构图我们可以了解到hibernate的大致工作流程:
(1)配置好hibernate的配置文件(hibernate.properties或者 hibernate.cfg.xml文件)和与类对应的配置文件后,启动服务器
(2)服务器通过实例化Configeration对象,读取hibernate.properties或者hibernate.cfg.xml文件的配置内容,并根据相关的需求建好表或者和表建立好映射关系
(3)通过实例化的Configeration对象就可以建立sessionFactory实例,进一步,通过sessionFactory实例可以创建session对象
(4)得到session之后,便可以对数据库进行增删改查操作了,除了比较复杂的全文搜索外,简单的操作都可以通过hibernate封装好的session内置方法来实现
(5)此外,还可以通过事物管理,表的关联来实现较为复杂的数据库设计

1.1.1.Hibernate是如何连接数据库

主要是通过hibernate.cfg.xml或者hibernater.properties配置文件中的配置
在这个文件中定义了数据库进行连接所需要的信息,包括JDBC驱动、用户名、密码、数据库方言等,configuration类借助dom4j的XML解析器解析设置环境,然后使用这些环境属性来生成 SessionFactory。这样这个sessionFactory生成的session就能成功获得数据库的连接。

1.1.2.Hibernate是如何进行数据库写操作

对数据库的写操作包括保存、更新和删除,当保存一个POJO持久对象时,触发Hibernate的保存事件监听器进行处理。Hibernate通过映射文件获得对象对应数据库表名以及属性所对应的表中的列名,然后通过反射机制持久化对象(实体对象)的各个属性,最终组织成向数据库插入新对象的SQL insert语句。调用了session.save()方法后,这个对象会标识成持久化状态存放在session中,对于Hibernate来说它就是一个持久化了的对象,但这个时候Hibernate还不会真正的执行insert语句,当进行session的刷新同部或事务提交时,Hibernate会把session缓存中的所有SQL语句一起执行,对于更新、删除操作也是采用类似的机制。
然后,提交事务并事务提交成功后,这些写操作就会被永久地保存进数据库中,所以,使用session对数据库操作还依赖于Hibernate事务的处理。如果设置了二级缓存,那么这些操作会被同步到二级缓存中,Hibernate对数据库最终操作也是依赖于底层JDBC对数据库进行。

1.1.3.Hibernate 如何从数据库中载入对象

当使用session.load()载入对象时,可以设置是否采用延迟加载,如果延迟加载,那么load返回的对象实际是CGLIB或javassist返回的代理类,它的非主键属性都是空的,这对于对象集合属性很有效。 Hibernate以此来节约内存,当真正需要读取对象时,Hibernate会先尝试从session缓存中读取,如果session缓存中数据不存在或者是脏数据并且配置了二级缓存,Hibernate尝试从二级缓存中检索数据,否则Hibernate会根据对象类型,主键等信息组织select语句到数据中读取,再把select结果组织成对象返回。

1.1.4.Hibernate如何进行数据库查询操作

Hibernate提供SQL HQL Criteria查询方式。HQL是其中运用最广泛的查询方式。用户使用session.createQuery()方法以一条HQL语句为参数创建 Query查询对象后,Hibernate会使用Anltr库把HQL语句解析成JDBC可以识别的SQL语句,如果设置了查询缓存,那么执行 Query.list()时,Hibernate会先对查询缓存进行查询,如果查询缓存不存在,再使用select语句查询数据库。

1.2 hibernate体系结构

这里写图片描述
针对以上的Hibernate全面解决方案架构图:
(1)SessionFactory:这是Hibernate的关键对象,它是单个数据库映射关系经过编译后的内存镜像,它也是线程安全的。它是生成Session的工厂,本身要应用到ConnectionProvider,该对象可以在进程和集群的级别上,为那些事务之间可以重用的数据提供可选的二级缓存。
(2)Session:它是应用程序和持久存储层之间交互操作的一个单线程对象。它也是Hibernate持久化操作的关键对象,所有的持久化对象必须在Session的管理下才能够进行持久化操作。此对象的生存周期很短,其隐藏了JDBC连接,也是Transaction 的工厂。Session对象有一个一级缓存,现实执行Flush之前,所有的持久化操作的数据都在缓存中Session对象处。
(3)持久化对象:系统创建的POJO实例一旦与特定Session关联,并对应数据表的指定记录,那该对象就处于持久化状态,这一系列的对象都被称为持久化对象。程序中对持久化对象的修改,都将自动转换为持久层的修改。持久化对象完全可以是普通的Java Beans/POJO,唯一的特殊性是它们正与Session关联着。
(4)瞬态对象和脱管对象:系统进行new关键字进行创建的Java 实例,没有Session 相关联,此时处于瞬态。瞬态实例可能是在被应用程序实例化后,尚未进行持久化的对象。如果一个曾今持久化过的实例,但因为Session的关闭而转换为脱管状态。
(5)事务(Transaction):代表一次原子操作,它具有数据库事务的概念。但它通过抽象,将应用程序从底层的具体的JDBC、JTA和CORBA事务中隔离开。在某些情况下,一个Session 之内可能包含多个Transaction对象。虽然事务操作是可选的,但是所有的持久化操作都应该在事务管理下进行,即使是只读操作。
(6)连接提供者(ConnectionProvider):它是生成JDBC的连接的工厂,同时具备连接池的作用。他通过抽象将底层的DataSource和DriverManager隔离开。这个对象无需应用程序直接访问,仅在应用程序需要扩展时使用。
(7)事务工厂(TransactionFactory):他是生成Transaction对象实例的工厂。该对象也无需应用程序的直接访问。
Hibernate进行持久化操作离不开SessionFactory对象,这个对象是整个数据库映射关系经过编译后的内存镜像,该对象的openSession()方法可打开Session对象。SessionFactory对想是由Configuration对象产生。
每个Hibernate配置文件对应一个configuration对象。在极端情况下,不使用任何配置文件,也可以创建Configuration对象。

1.3 创建Configuration对象

org.hibernate.cfg.Configuration实例代表一个应用程序到SQL数据库的映射配置,Configuration提供了一个buildSessionFactory()方法,该方法可以产生一个不可变的SessionFactory对象。
你可以直接实例化Configuration来获取一个实例,并为它指定一个Hibernate映射文件,如果映射文件在类加载路径中,则可以使用addResource()方法来添加映射定义文件。那么现在的问题就是如何创建Configuration对象呢?
随着Hibernate 所使用的配置文件的不同,创建Configuration对象的方式也不相同。通常有几种配置Hibernate的方式:
(1)使用hibernate.properties文件作为配置文件。
(2)使用hibernate.cfg.xml文件作为配置文件。
(3)不使用任何的配置文件,以编码方式来创建Configuration对象。
请注意:Configuration对象的唯一作用就是创建SessionFactory实例,所以它才被设计成为启动期间对象,而一旦SessionFactory对象创建完成,它就被丢弃了。

1.3.1. 使用hibernateproperties作为配置文件

对于hibernate.properties作为配置文件的方式,比较适合于初学者。因为初学者往往很难记住该配置文件的格式,以及需要配置哪些属性。在Hibernate发布包的etc路径下,提供了一个hibernate.properties文件,该文件列出了Hibernate 的所有属性。每个配置段都给出了大致的注释,用户只要取消所需配置段的注释,就可以快速配置Hibernate和数据库的链接此处给出使用hibernate.properties文件创建Configuration对象的方法。

//实例化configuration对象
Configuration cfg = new Configuration()
//多次调用addResource()方法,添加映射文件
.addResource("Item.hbm.xml")
.addResource("Bid.hbm.xml");

查看hibernate.properties文件发现,该文件没有提供Hibernate映射文件的方式。因此使用hibernate.properties文件来作为配置文件时,必须使用Configuration的.addResource()方法,使用该方法来添加映射文件。
注意:正如上面的代码所示,使用hibernate.properties文件配置Hibernate的属性固然简单,但是因为要手动添加映射文件,当映射文件极其多时,这是一件非常催人泪下的事情。这也就是在实际开发中,不常使用hibernate.properties文件作为配置文件的原因。
当然还有另一种添加配置文件的策略,因为映射文件和持久化类是一一对应的,可以通过Configuration对象来添加持久化类,让Hibernate自己来搜索映射文件。

//实例化configuration对象
Configuration cfg = new Configuration)
//多次调用addClass()方法,直接添加持久化类
.addClass(ppp.Item.class)
.addClass(ppp.BId.class);

1.3.2. 使用hibernate.cfg.xml作为配置文件

前面已经看到使用hibernate.properties作为配置文件的情形。因为hibernate.cfg.xml中已经添加了hibernate的映射文件,采用这种配置文件创建configuration对象实例由以下代码实现:

//实例化configuration对象
Configuration cfg = new Configuration()
//configure()方法将会负责加载hibernate.cfg.xml文件
.configure()

需要注意的是:在通过new关键字创建Configuration对象之后,不要忘记调用configure()方法。

2. hibernate三种状态

这里写图片描述
上图就是hibernate的三种状态。接下来我们详细分析下每一种状态。

2.1. transient(瞬时状态)

其实就是new一个对象后,还没有保存到数据库中,未持久化

--session begin--
Car car = new Car();
car.setName("car1");
car.setColor("blue");
//car处于Transient(瞬时状态),在session缓存中不存在car对象
session.save(car);
//执行save后,session缓存中和数据库中存在car对象,状态转换为【持久状态】     
--session commit--

执行完毕save以后,这个比较好理解,对象就变为持久化,会发出一条sql语句:
Hibernate: insert into t_car (id, name, color) values (?, ?, ?)

2.2 persistent(持久状态)

其实持久化状态就是已经被保存到数据库中,session中也存在该对象
2.1)持久化后执行update动作

--session begin--
Car car = new Car();
car.setName("car1");
car.setColor("blue");
//car处于Transient(瞬时状态),在session缓存中不存在car对象
session.save(car);
//执行save后,session缓存中和数据库中存在car对象,状态转换为持久状态        
car.setColor("red"); 
//这个car对象会与session缓存中car对象进行比较,如果不同,就发出update语句
--session commit--

当car持久化后,又重新修改了属性color值,在事务commit提交时,hibernate比较当前对象和session缓存中的car对象是否相同,如果相同,则不会发送update语句,否则,会发出update语句。

Hibernate: insert into t_car ((id, name, color) values (?, ?, ?)
Hibernate: update t_car set color=? where id=?

2.2)持久化后多次调用session.update

--session begin--
Car car = new Car();
car.setName("car1");
car.setColor("blue");
//car处于Transient(瞬时状态),在session缓存中不存在car对象
session.save(car);
//执行save后,session缓存中和数据库中存在car对象,状态转换为持久状态          car.setColor("red");   
session.update(car);   
car.setColor("black");
session.update(car);        
//这个car对象会与session缓存中car对象进行比较,如果不同,就发出update语句 
--session commit--

!!重点就是这里!!:
为什么session执行update或者save了多次,只提交一次update语句?
注意session级别里面的缓存,只有在commit的时候才会去比较对象是否不同,不同才会发出
sql语句执行。

Hibernate: insert into t_car ((id, name, color) values (?, ?, ?)
Hibernate: update t_car set color=? where id=?

2.3)持久化后session.clear
大家看完上面的说明以后,hibernate最重要的是session级别缓存,多次update持久化对象只会执行一次语句。但是clear以后会怎样?
顾名思义:清除session中的缓存,既然session里面缓存不存在那个对象了,你猜会怎样?

Car car = session.get(Car.class,1); 
Car car2 = session.get(Car.class,1);    
Car car3 = session.get(Car.class,1);
//上面不管获取几次id=1的car对象只会发一条sql语句,因为去session缓存里面获取 
session.clear();
//但是session缓存被清空了,下面还会发一次sql查询语句    
Car car4 = session.get(Car.class,1);

如果已经get一次对象保存到session缓存中,你如果重复发送多少条get对象Car语句,hibernate都是先去缓存里获取,也就是只发一条sql语句去查询,但是一旦session被clear,然后缓存中没有了,会重新再发sql去获取。

Hibernate: select car0_.id as id0_0_, car0_.name as name0_0_, car0_.color as color0_0_ from t_car car0_ where car0_.id=?
Hibernate: select car0_.id as id0_0_, car0_.name as name0_0_, car0_.color as color0_0_ from t_car car0_ where car0_.id=?

2.4)持久化后session.flush()
想必大家知道session的强大作用了,当执行flush的时候会发现什么?
顾名思义:强制缓存的内容与数据库内容做同步,类似于提交

Car car = session.get(Car.class,1);
a.setColor("aa");
a.setColor("bb");
//明显只会发送一条sql的update语句  
--session commit--

如上因为hibernate只会在事务commit提交时,去比较缓存对象是否不同,发送一条语句更新

Hibernate: update t_car set color=? where id=?

如果加了flush会怎样?

Car car = session.get(Car.class,1);
a.setColor("aa");
//发送一条sql的update语句
sessoin.flush();//此时session强制合数据库同步为aa,所以需要先发送同步"aa"语句
//因为缓存已经和数据库进行同步了,还会再发送一条sql的update语句进行同步"bb"
a.setColor("bb");   
--session commit--
Hibernate: update t_car set color=? where id=?
Hibernate: update t_car set color=? where id=?

如果加了flush,需要发送两条更新语句,因为session被强制同步了

2.3、detached(离线状态)

其实离线状态就是数据库中有,但是session中不存在该对象。

--session begin--数据库中已经存在id为1的car对象
 Car car = new Car();
//数据库已经存在一个Id=1的对象,现在又创建一个一样的Id
 car.setId(1);
 car.setName("second");
 session.saveOrUpdate(car); 

saveOrUpdate看的出来,如果对象是离线状态就执行update操作,如果是瞬时状态就执行Save操作。
所以说到最后,hibernate最重要的就是它的session管理,在开发上带来了一些便利。
**瞬时对象:session和数据库中都没用该对象
持久对象:数据库和session中都存在该对象
离线对象:数据库中存在,但是session里面不存在该对象**

相关TAG标签
上一篇:静态路由和动态路由_路由汇总和默认路由
下一篇:字符设备驱动之按键定时器消抖实现方法
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站