hibernate的工作原理

1、hibernate 简介:

         hibernate是一个开源框架,它是对象关联关系映射的框架,它对JDBC做了轻量级的封装,而我们java程序员可以使用面向对象的思想来操纵数据库。
hibernate核心接口
session:负责被持久化对象CRUD操作
sessionFactory:负责初始化hibernate,创建session对象
configuration:负责配置并启动hibernate,创建SessionFactory
Transaction:负责事物相关的操作
Query和Criteria接口:负责执行各种数据库查询

  2、hibernate工作原理:

 

  • ①读取并解析配置文件。
  • ②读取并解析映射信息,创建SessionFactory。
  • ③打开Session
  • ④创建事务Transaction。
  • ⑤持久化操作。
  • ⑥提交事务。
  • ⑦关闭Session。
  • ⑧关闭SessionFactory。

概述:

  • Hibernate可以理解为是一个中间件,它负责把Java程序的SQL语句接收过来并发送到数据库,而数据库返回来的信息由Hibernate接收后直接生成一个对象传给Java。
  • 首先,必须有数据库文件,假设数据库里有一个employee员工表,SQL语句如下:
create table employee(id Number(10),name varchar2(20))
  • 其次,Hibernate有两个特有的文件,一个是以.cfg.xml结尾的文件,一个是以.hbm.xml结尾的文件。

详述:

1、关于cfg.xml文件:

  • cfg.xml文件的作用就是连接数据库。文件内部其实就是一个由user、password、url、driver组成的连接库的基本信息。文件的内容如下:

    
        用户名
        jdbc:oracle:thin:@localhost:1521:数据库名
        密码
        oracle.jdbc.OracleDriver
        org.Hibernate.dialect.OracleDialect
          
    
  • 简单分析一下这个文件: 
    • ①包含的是程序里面的configuration实例信息。通过这个实例的方法configure,我们可以从mapping中得到对应的表的信息和类的信息。
    • ② < session-factory > 这个标签是程序中通过configure的方法BuildSessionFactory得到的一个SessionFactory对象,这个对象可以理解为一个statement。我们对数据库的所有操作都是通过它的一系列方法来实现。
    • ③property dialect 都是Hibernate的一些属性设置,我们可以设置很多Property,其中一些是必须的,一些是可选的。

2、关于hbm.xml文件

  • hbm.xml文件是对数据库中表的映射文件,可以由这个文件指出哪个类对应着哪个表,而且还指出哪个类中的属性对应着表中的哪个字段。文件内容如下:

    
        
            
        
        
    
  • 上面文件里面有一行语句

可以实现id自动增加,也就是说,如果往数据库中插入一个name,那么id就自动加1。

  • 这个文件解释了< Hibernate-mapping >所包含的就是cfg.xml文件中说的mapping。Java类中配置得到的mapping就是从这个文件里面读取出来的。如:
  • 就是先指定了类对应的表。文件中的语句就是指定表中的字段与类中的属性的对应关系。
  • 下面再说说要实现功能所需的Java类,有两个:一个是employee类,一个是Test类。 
    employee类是一个简单的JavaBean。它是先和数据库字段对应,然后取值的。
package src;

public class Employee{
    private int id;
    private String name;

    public void setId(int id){
        this.id = id;
    }

    public int getId(){
        return id;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

再看一下Test类:

package src;

import org.hibernate.*;
import org.hibernate.cfg.*;

public class Test{
    try{
        SessionFactory sessionfactory = new Configuration().configure().BuildSessionFactory();
        Session session = sessionfactory.opensession();
        Transaction transaction = session.beginTransaction();
        for(int i = 0;i<3;i++){
            Employee employee = new Employee();
            employee.setName("begin go "+i);
            session.save(employee);
        }
        transcation.commit();
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        session.close();
    }
}

对代码分析如下:

  • 1、语句
SessionFactory sessionfactory = new Configuration().configure().BuildSessionFactory();
  • 1得到configuration的实例。然后通过configure()读取mapping对应的hbm.xml文件的信息。
  • 2、通过BuildSessionFactory得到SessionFactory对象。
  • 3、通过opensession()建立连接。Session就是指一个Session被建立,这里等于是一个connection被建立好。
  • 4、通过Session对象开启事务(Transaction)相当于conn.setAutoCommit(false)先不递交,最后通过另外一个方法递交。
  • 5、循环语句把employee实例化。
  • 6、实例化后就可以用其中的方法,如setName方法等。
  • 7、每次都要用session来save一下,一个对象set之后要保存在session中。
  • 8、最后递交commit().

  • 之所以没有SQL语句,是因为Hibernate的特性,对数据库的操作就是对对象的操作,这就是OR-Mapping的本质。


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

1. 对于Hibernate get方法,Hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查询数据库,数据 库中没有就返回null。这个相对比较简单,也没有太大的争议。主要要说明的一点就是在这个版本(bibernate3.2以上)中get方法也会查找二级缓存!

2. Hibernate load方法加载实体对象的时候,根据映射文件上类级别的lazy属性的配置(默认为true),分情况讨论: 

(1)若为true,则首先在Session缓存中查找,看看该id对应的对象是否存在,不存在则使用延迟加载,返回实体的代理类对象(该代理类为实体类的子类,由CGLIB动态生成)。等到具体使用该对象(除获取OID以外)的时候,再查询二级缓存和数据库,若仍没发现符合条件的记录,则会抛出一个ObjectNotFoundException。

(2)若为false,就跟Hibernateget方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个ObjectNotFoundException。

这里get和load有两个重要区别: 

如果未能发现符合条件的记录,Hibernate get方法返回null,而load方法会抛出一个ObjectNotFoundException。

load方法可返回没有加载实体数据的代 理类实例,而get方法永远返回有实体数据的对象。

(对于load和get方法返回类型:好多书中都说:“get方法永远只返回实体类”,实际上并不正 确,get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加 载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数 据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。)

总之对于get和load的根本区别,一句话,hibernate对于 load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方 法,hibernate一定要获取到真实的数据,否则返回null。

4、Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)

类与类之间的关系主要体现在表与表之间的关系进行操作,它们都市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的many-to-one、one-to-many、many-to-many、

说下Hibernate的缓存机制:

Hibernate缓存的作用:
    Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据
Hibernate缓存分类:
  Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存
Hibernate一级缓存又称为“Session的缓存”,它是内置的,意思就是说,只要你使用hibernate就必须使用session缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。在第一级缓存中,持久化类的每个实例都具有唯一的OID。 
Hibernate二级缓存又称为“SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。

什么样的数据适合存放到第二级缓存中?   
1 很少被修改的数据   
2 不是很重要的数据,允许出现偶尔并发的数据   
3 不会被并发访问的数据   
4 常量数据   
不适合存放到第二级缓存的数据?   
1经常被修改的数据   
2 .绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发   
3 与其他应用共享的数据。 

Hibernate查找对象如何应用缓存?
当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照ID放入到缓存
删除、更新、增加数据的时候,同时更新缓存

Hibernate管理缓存实例
无论何时,我们在管理Hibernate缓存(Managing the caches)时,当你给save()、update()或saveOrUpdate()方法传递一个对象时,或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。 
当随后flush()方法被调用时,对象的状态会和数据库取得同步。 如果你不希望此同步操作发生,或者你正处理大量对象、需要对有效管理内存时,你可以调用evict() 方法,从一级缓存中去掉这些对象及其集合。 

你可能感兴趣的:(Java)