javaEE --- Hibernate

                    Hibernate

1.什么是Hibernate?

Hibernate是一个采用ORM(Object/Relation Mapping对象关系映射)机制持久层的开源框架,对JDBC做了轻量级的封装,从而使程序员可以以面向对象的思想来操作数据库。完成数据的持久化操作。


2.Hibernate的核心思想?

Hibernate 的核心思想就是面向对象来操作数据库,而这种面向对象的思想又是基于ORM机制来实现的。

ORM将表与表之间的关系映射为对象与对象之间的关系。这样简化了持久层的代码,减轻了程序员的负担。



3.Hibernate的核心接口?


Session接口:负责执行持久化的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)

注意:

Hibernate中的Session 和Httpsession 是两个完全不同的概念,后者一般称为用户Session


SessionFactory接口:负责初始化Hibernate,充当数据存储源的代理,并负责创建Session对象,sf.openSession();


configuration接口:负责配置和启动Hibernate,创建SessionFactory对象。


Transaction接口:负责事务相关的操作,它是可选的,程序员也可以设计编写自己的底层事务处理代码。


Query和Criteria接口:二者主要负责执行各种数据库的查询功能,可以用SQL和HQL两种 查询方式


4.Hibernate 的运行流程/原理&&WHY 要使用Hibernate?

        原理:

a.通过Configuration 读取并解析Hibernate.cfg.xml 配置文件

b.由Hibernate.cfg.xml 中的<mapping resource="com/XX/XX.hbm.xml" />读取并解析映射信息

c.通过  SessionFactory sf= config.buildSessionFactory(); 创建SessionFactory

d. Session session =sf.openSession();  创建session

e.Transaction tx = session.beginTransaction();开启事务

f.Persistence  Operate   操作数据,持久化操作。

g.tx.commit();  提交事务

h.session.close();关闭session

j.SessionFactory.close(); 关闭SessionFactory


     WHY:

          1.JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。它很大程度的简化DAO层的编码工作。
3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。


5.简述Hibernate的缓存机制,以及为什么要用缓存机制?

①为什么要用?

  Hibernate是一个持久层框架,要经常访问物理数据库,为了降低应用程序对物理数据库的访问频次,变制造出了缓存这个机制,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中数据的复制,应用程序在运行时,从缓存中读取数据,在特定的时刻或时间缓存会同步缓存和物理数据库中的数据

② Hibernate的缓存机制?

    首先要知道什么是缓存?缓存缓存就是把以前从数据库中查询出来和使用过的对象保存在内存中(一个数据结构中),这个数据结构通常是或类似Hashmap,当以后要使用某个对象时,先查询缓存中是否有这个对象,如果有则使用缓存中的对象,如果没有则去查询数据库,并将查询出来的对象保存在缓存中,以便下次使用.


     Hibernate的缓存主要包括两大类:Hibernate一级缓存(Session缓存)、Hibernate二级缓存(SessionFactory缓存)

    Session缓存:是内置的,不能卸载,Session缓存是事务范围内的缓存,Session对象的生命周期对应着一个数据库事务或者一个应用事务。在一级缓存中,持久化类每个实例都具有唯一的OID。

     SessionFactory缓存:由于SessionFactory对象的生命周期与整个应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或集群内的缓存,有可能出现并发问题,因此要采取适当的并发访问策略,该策略为缓存的数据提供了事务隔离级别。


   那么问题来了,什么样的数据适合放在二级缓存中,什么样的数据又不适合呢?

   适合放在二级缓存中的数据:

1)很少被修改的数据。

  2)不是很重要的数据,可以偶尔出出现并发的数据。

3)不会被并发访问的数据。

4)常量数据。


    不适合放在二级缓存中的数据:

1)经常改动的数据。

2)绝对不允许出现并发的数据(如财务数据) 。

3)去其他应用共享的数据。




6.简述Hibernate  和JDBC 的异同、优缺点?

 ①相同点:

◆两者都是JAVA的数据库操作中间件。

◆两者对于数据库进行直接操作的对象都不是线程安全的,都需要及时关闭。

◆两者都可以对数据库的更新操作进行显式的事务处理。

②不同点:

◆使用的SQL语言不同:JDBC使用的是基于关系型数据库的标准SQL语言,Hibernate使用的是HQL(Hibernate query language)语言。

◆操作的对象不同:JDBC操作的是数据,将数据通过SQL语句直接传送到数据库中执行,Hibernate操作的是持久化对象,由底层持久化对象的数据更新到数据库中。

◆数据状态不同:JDBC操作的数据是“瞬时”的,变量的值无法与数据库中的值保持一致,而Hibernate操作的数据是可持久的,即持久化对象的数据属性的值是可以跟数据库中的值保持一致的。

③优缺点:

JDBC与Hibernate在性能上相比,JDBC灵活性有优势。

而Hibernate在易学性,易用性上有些优势。

当用到很多复杂的多表联查和复杂的数据库操作时,JDBC有优势。


7.Hibernate 中session.get() 和session.load()的区别?

----------------------------------------------------------------------------------------------------------------------------------------------------

①get()不支持lazy[延迟加载],load() 支持lazy;

lazy表示 只有用到的时候才加载数据。

 如:Student student = (Student)session.load(Student.class,1);  //不会发出SQL语句
       student.getName();   //这条语句才会发出SQL语句

 而session.get(Student.class,1); 直接发出SQL语句。

 ②get加载数据,当数据库中不存在相应的数据时,则返回null

    load加载数据,当数据库中不存在相应的数据时,则会那么抛出ObjectNotFoundException

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。

其区别在于:

①如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。
②load支持延迟加载,get不支持
load方法可返回实体的代理类实例,而get方法永远直接返回实体类。
load方法可以充分利用内部缓存和二级缓存中的现有数据,get方法则仅仅在内部缓存中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL完成数据读取。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Session在加载实体对象时,将经过的过程:


首先,Hibernate中维持了两级缓存。第一级缓存由Session实例维护,其中保持了Session当前所有关联实体的数据,也称为内部缓存。而第二级缓存则存在于SessionFactory层次,由当前所有由本SessionFactory构造的Session实例共享。出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。
之后,Session会在当前“NonExists”记录中进行查找,如果“NonExists”记录中存在同样的查询条件,则返回null。“NonExists”记录了当前Session实例在之前所有查询操作中,未能查询到有效数据的查询条件(相当于一个查询黑名单列表)。如此一来,如果Session中一个无效的查询条件重复出现,即可迅速作出判断,从而获得最佳的性能表现。

对于load方法而言,如果内部缓存中未发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。
如在缓存中未发现有效数据,则发起数据库查询操作(Select SQL),如经过查询未发现对应记录,则将此次查询的信息在“NonExists”中加以记录,并返回null。
根据映射配置和Select SQL得到的ResultSet,创建对应的数据对象。
将其数据对象纳入当前Session实体管理容器(一级缓存)。
执行Interceptor.onLoad方法(如果有对应的Interceptor)。
将数据对象纳入二级缓存。
如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。
返回数据对象。


8.什么是Criteria?

Criteria 是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现、SQL语句如何编写,是Hibernate框架的核心查询对象。
Hibernate 定义了CriteriaSpecification接口规范用来完成面向对象的条件查询,Criteria 就是CriteriaSpecification的子接口。
Criteria的基本用法
①获取一个Criteria查询对象
Criteria criteria = session.createCriteria(Employee.class);
      ②使用Restrictions添加查询条件

criteria.add(Restrictions.eq("name","人力资源部"));

  ③返回查询结果

criteria.list();

Criteria的条件查询:

           通过.add(Restrictions.条件方法())来查询

            Restrictions的方法:

•eq() 等于 ==
•ne() 不等于<>
•gt() 大于 》
•ge() 大于等于 >=
•lt() 小于 <
•le() 小于等于 <=
•isNull() 是否为空
•isNotNull() 不为空 

•in("属性名","集合或数组")
•Restrictions.not( Restrictions.in())
•between(“属性名”,值1,值2)
•Restrictions.not(Restrictions.between())
•allEq() 利用Map()来进行多个等于的限制
•and(条件1,条件2) 或 conjunction()
•or 或多个或disjunction()
•sqlRestriction 用SQL限定查询

 Criteria的排序:

 Criteria.addOrder(order.desc());

Criteria.addOrder(order.esc())    


Criteria的分页:

 employeeCriteria.setFirstResult(0);  //设置记录的起始位置0代表第一条记录。

employeeCriteria.setMaxResults(2)//设置一次查询的记录条数.


9.Hibernate中对象有哪几种状态?

1. 瞬时状态 (Transient)

当我们通过Java的new关键字来生成一个实体对象时,这时这个实体对象就处于自由状态,如下:
 Customer customer=new Customer(“zx”,27,images);
这时customer对象就处于自由状态,为什么说customer对象处于自由状态呢?这是因为,此时customer只是通过JVM获得了一块内存空间,还并没有通过Session对象的save()方法保存进数据库,因此也就还没有纳入Hibernate的缓存管理中,也就是说customer对象现在还自由的游荡于Hibernate缓存管理之外。所以我们可以看出自由对象最大的特点就是,在数据库中不存在一条与它对应的记录。

瞬时对象特点:

(1) 不和 Session 实例关联

(2) 在数据库中没有和瞬时对象关联的记录

2. 持久状态 (Persistent)

持久化对象就是已经被保存进数据库的实体对象,并且这个实体对象现在还处于Hibernate的缓存管理之中。这是对该实体对象的任何修改,都会在清理缓存时同步到数据库中。如下所示:
Customer customer=new Customer(“zx”,27,images);
tx=session.beginTransaction();
session.save(customer);
customer=(Customer)session.load(Customer.class,”1”);
customer.setAge(28);
tx.commit();
这时我们并没有显示调用session.update()方法来保存更新,但是对实体对象的修改还是会同步更新到数据库中,因为此时customer对象通过save方法保存进数据库后,已经是持久化对象了,然后通过load方法再次加载它,它仍然是持久化对象,所以它还处于Hibernate缓存的管理之中,这时当执行tx.commit()方法时,Hibernate会自动清理缓存,并且自动将持久化对象的属性变化同步到到数据库中。

持久的实例在数据库中有对应的记录,并拥有一个持久化标识 (identifier).

持久对象总是与 Session 和 Transaction 相关联,在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而必须在 Transaction 终止,也就是执行 commit() 之后,才在数据库中真正运行 SQL 进行变更,持久对象的状态才会与数据库进行同步。在同步之前的持久对象称为脏 (dirty) 对象。

瞬时对象转为持久对象:

(1) 通过 Session 的 save() 和 saveOrUpdate() 方法把一个瞬时对象与数据库相关联,这个瞬时对象就成为持久化对象。

(2) 使用 fine(),get(),load() 和 iterater() 待方法查询到的数据对象,将成为持久化对象。

持久化对象的特点:

(1) 和 Session 实例关联

(2) 在数据库中有和持久对象关联的记录

3. 脱管状态 (Detached)

当一个持久化对象,脱离开Hibernate的缓存管理后,它就处于游离状态,游离对象和自由对象的最大区别在于,游离对象在数据库中可能还存在一条与它对应的记录,只是现在这个游离对象脱离了Hibernate的缓存管理,而自由对象不会在数据库中出现与它对应的数据记录。如下所示:
Customer customer=new Customer(“zx”,27,images);
tx=session.beginTransaction();
session.save(customer);
customer=(Customer)session.load(Customer.class,”1”);
customer.setAge(28);
tx.commit();
session.close();
当session关闭后,customer对象就不处于Hibernate的缓存管理之中了,但是此时在数据库中还存在一条与customer对象对应的数据记录,所以此时customer对象处于游离态

与持久对象关联的 Session 被关闭后,对象就变为脱管对象。对脱管对象的引用依然有效,对象可继续被修改。

脱管对象特点:

(1) 本质上和瞬时对象相同

(2) 只是比爱瞬时对象多了一个数据库记录标识值 id.

持久对象转为脱管对象:

当执行 close() 或 clear(),evict() 之后,持久对象会变为脱管对象。

瞬时对象转为持久对象:

通过 Session 的 update(),saveOrUpdate() 和 lock() 等方法,把脱管对象变为持久对象。

三种状态相互转化的状态图如下:

Hibernate三种状态

4 .结合 save(),update(),saveOrUpdate() 方法说明对象的状态

(1)Save() 方法将瞬时对象保存到数据库,对象的临时状态将变为持久化状态。当对象在持久化状态时,它一直位于 Session 的缓存中,对它的任何操作在事务提交时都将同步到数据库,因此,对一个已经持久的对象调用 save()或 update() 方法是没有意义的。如:

Student stu = new Strudnet();

stu.setCarId(“200234567”);

stu.setId(“100”);

// 打开 Session, 开启事务

session.save(stu);

stu.setCardId(“20076548”);

session.save(stu); // 无效

session.update(stu); // 无效

// 提交事务,关闭 Session

(2)update() 方法两种用途重新关联脱管对象为持久化状态对象,显示调用 update() 以更新对象。调用 update() 只为了关联一个脱管对象到持久状态,当对象已经是持久状态时,调用 update() 就没有多大意义了。如:

// 打开 session ,开启事务 

stu = (Student)session.get(Student.class,”123456”);

stu.setName(“Body”);

session.update(stu); // 由于 stu 是持久对象,必然位于 Session 缓冲中,

对 stu 所做的变更将 // 被同步到数据库中。所以 update() 是没有意义的,可以不要这句效果一样的。

// 提交事务,关闭 Session

Hibernate 总是执行 update 语句,不管这个脱管对象在离开 Session 之后有没有更改过,在清理缓存时 Hibernate总是发送一条 update 语句,以确保脱管对象和数据库记录的数据一致,如:

Student stu = new Strudnet();

stu.setCarId(“1234”);

// 打开 Session1, 开启事务

session1.save(stu);

// 提交事务,关闭 Session1

stu.set(“4567”); // 对脱管对象进行更改

// 打开 Session2, 开启事务

session2.update(stu);

// 提交事务,关闭 Session2

注:即使把 session2.update(stu); 这句去掉,提交事务时仍然会执行一条 update() 语句。

如果希望只有脱管对象改变了, Hibernate 才生成 update 语句,可以把映射文件中 <class> 标签的 select-before-update 设为 true, 这种会先发送一条 select 语句取得数据库中的值,判断值是否相同,如果相同就不执行 update语句。不过这种做法有一定的缺点,每次 update 语句之前总是要发送一条多余的 select 语句,影响性能。对于偶尔更改的类,设置才是有效的,对于经常要更改的类这样做是影响效率的。

(3)saveOrUpdate() 方法兼具 save() 和 update() 方法的功能,对于传入的对象, saveOrUpdate() 首先判断其是脱管对象还是临时对象,然后调用合适的方法。






上述内容用于自己对相关知识点的总结、归纳、回顾.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值