Hibernate 基本介绍

来源:互联网 发布:阿里云os电视系统破解 编辑:程序博客网 时间:2024/05/16 19:38

构架hibernate的介绍

-----------------------------------------------------------------------------------------------------------------
一. 什么是Hibernate?
     Hibernate是ORM下的一个子产品,ORM的全称是Object Relation Mapping,翻译成中文后是对象关系映射,该技术实现了JAVA对象与数据库之间的关系映射,ORM下面有很多种技术实现,比如Ibatis,Entity Bean,Hibernate等,其中Hibernate是一个优秀的ORM实现。


二. Hibernate优缺点
    Hibernate是面向对象的JDBC封装。Hibernate是一个基于JDBC的主流持久化框架,它的核心机制就是对象与数据库的关系映射,通过它的核心机制可以简化DAO层的编码工作,使DAO层的代码更加简洁易懂,不像以前的JDBC和Ibatis需要写大量的SQL语句,Hibernate不用写SQL语句,它根据实体对象实现动态生存SQL语句。因为它是个轻量级框架,所以映射的灵活性很出色,能够实现实体对象间的1-1到n-n的各种复杂关系,并且支持各种关系数据库。由于Hibernate本身是个独立的框架,所以它不需要任何web server或application server的支持。
缺点就是查询大量数据时,因为它自动生存SQL语句,所以性能方面就会下降很多。


三. Hibernate 的工作原理:
首先获得SessionFactory 的对象

 Configuration configuration = new Configuration().configure();//采用默认的hibernate.cfg.xml来启动一个Configuration的实例,也可以采用自定义方式:new Configuration().configure("/***/*.cfg.xml");
 sessionFactory = configuration.buildSessionFactory();// 由Configuration的实例来创建一个SessionFactory实例
然后获得session 的对象

Session session = sessionFactory.openSession();
其次获得Transaction 的对象


Transaction tx = session.beginTransaction();
执行相关的数据库操作:增,删,改,查

session.save(user); //增加, user 是User 类的对象
session.delete(user); //删除
session.update(user); //更新
Query query = session.createQuery(“from User”); //查询List list = query.list();
提交事务

tx.commit();
如果有异常,我们还要作事务的回滚,恢复到操作之前

tx.rollback();
最后还要关闭session,释放资源
session.close();


四. Hibernate 的5个核心接口及作用
Configuration 接口:配置Hibernate,根据其启动hibernate,创建SessionFactory 对象;


SessionFactory 接口:初始化Hibernate,充当数据存储源的代理,创建session 对象,sessionFactory 是线程安全的,意味着它的同一个实例可以被应用的多个线程共享,是重量级、二级缓存;


Session 接口:负责保存、更新、删除、加载和查询对象,是线程不安全的,避免多个线程共享同一个session,是轻量级、一级缓存;


Transaction 接口:管理事务;


Query 和Criteria  接口:执行数据库的查询。


五. hibernate数据查询的几种方式
  ①使用主键id加载对象(load(),get());
  ②通过对象导航,比如通过stu.getTeam()得到team的实例;
  ③使用hql;
  ④使用qbc(query by criteria)
  ⑤直接使用sql语句取得记录集;
一般都使用后面三种方式.
注意.hql是面向对象的查询.语法和sql是基本一样的.不区分大小写的,但是注意的是对象与对象.必须遵循对象的大小写.因为hql是对像查询..同时我们必须清楚.hql只能取得对象,而不支持uid(update,insert.delete)
总结:
hql功能很强大,适合各种情况,但是动态条件查询构造起来很不方便.
criteria 最适合动态查询,但不太适合统计查询,qbe还不够强大.只适合简单的查询.
nativesql可以实现特定的数据库的sql.但是可移植性并不好.
针对web应用来说,大部分常规查询都是动态条件查询,所以首先criteria,并且h 3提供的detachedcriteria,可以在web层构造好detachedcriteria再进入session执行查询.但是涉及到统计查询和非常复杂的关联查询.criteria就无能为力了.这种情况下选择使用hql.最后如果涉及到使用某些数据库的特性的时候,就只有选择 nativesql了.
hql常用来进行实体检索.这个时候要注意返回的list中的元素是实体还是实体数组.如果hql进行实体属性查询,当查询两个以上的属性时,list中的元素就是属性数组了.
qbc最大的用途在与动态查询.它不会忽略配置文件中的预先抓取策略.
使用本地sql检索必须检索对象的所有属性.


. Hibernate是如何延迟加载?
当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,从而提高了服务器的性能。


.Hibernate 是如何处理事务的?
Hibernate 的事务实际上是底层的JDBC Transaction 的封装或者是JTA Transaction 的封装;默认情况下使用JDBCTransaction。
下面是在Hibernate的配置文件中添加JDBC事务或JTA事务:


<hibernate-configuration>
  <session-factory>
  ……
  <property name="hibernate.transaction.factory_class">
     net.sf.hibernate.transaction.JTATransactionFactory
     <!-net.sf.hibernate.transaction.JDBCTransactionFactory->
  </property>
  ……
  </session-factory>
</hibernate-configuration>
JDBC Transaction事务的实现:
Hibernate将事务管理委托给JDBC进行处理,其实现方式很简单,通过配置文件设定采用JDBC作为事务管理实现,事务实现代码如下:


session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
……
tx.commit();
JTA Transaction事务的实现:
JTA 提供了跨Session 的事务管理能力。这一点是与JDBC Transaction 最大的差异。
基于JDBC Transaction的Hibernate 事务管理机制而言,事务管理在Session 所依托的JDBC Connection中实现,事务周期限于Session的生命周期。而JTA事务管理则由JTA容器实现,JTA 容器对当前加入事务的众多Connection进行调度,实现其事务性要求。JTA的事务周期可横跨多个JDBC Connection生命周期。
同样对于基于JTA事务的Hibernate而言,JTA事务横跨可横跨多个Session。下面就是如何实现JTA事务管理的一个实例:


public class ClassA{
    public void save(TUser user){
      session = sessionFactory.openSession();
      session.save(user);
      session.close();
    }
    ……
}


public class ClassB{
    public void save (Order order){
        session = sessionFactory.openSession();
        session.save(order);
        session.close();
    }
    ……
}


public class ClassC{
    public void save(){
        ……
        session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        classA.save(user);
        classB.save(order);
        tx.commit();
        ……
    }
}

 

八. Hibernate如何实现数据批量删除或更新?
String sql = "delete from Person where name = ?";
Query query = session.createQuery(sql);//SQL语句”update”或”delete”
query.setString(0,"maozedong");
query.executeUpdate();

 

九.jdbc、hibernate、ibatis的区别
jdbc:
手动写sql,delete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。
select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。


ibatis:
半自动化,sql要手动写,delete、insert、update直接传入一个对象
select:直接返回一个对象


hibernate:
全自动,不写sql,由hibernate动态生存SQL语句,delete、insert、update直接传入一个对象
select:直接返回一个对象

 


十. Hibernate中get()与load()的区别:
1> 从返回结果上对比:
    load()方法检索不到的话会抛出org.hibernate.ObjectNotFoundException异常
    get()方法检索不到的话会返回null


2> 从检索执行机制上对比:
    get()方法和find()方法都是直接从数据库中检索,而load方法的执行则比较复杂 ,首先查找session的persistent Context中是否有缓存,如果有则直接返回,如果没有则判断是否是lazy,如果不是直接访问数据库检索,查到记录返回,查不到抛出异常 ;如果是lazy则需要建立代理对象,对象的initialized属性为false,target属性为null ,在访问获得的代理对象的属性时,检索数据库,如果找到记录则把该记录的对象复制到代理对象的target上,并将initialized=true,如果找不到就抛出异常 。


3> 根本区别说明
    如果你使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库中是一定存在的,所以它可以放心的使用,它可以放心的使用代理来延迟加载该对象。在用到对象中的其他属性数据时才查询数据库,但是万一数据库中不存在该记录,那没办法,只能抛异常。所说的load方法抛异常是指在使用该对象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时(注意:这就是由于“延迟加载”在作怪)


    由于session中的缓存对于hibernate来说是个相当廉价的资源,所以在load时会先查一下session缓存看看该id对应的对象是否存在,不存在则创建代理。所以如果你知道该id在数据库中一定有对应记录存在就可以使用load方法来实现延迟加载。


    对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库,数据库中没有就返回null。


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


    get方法首先查询session缓存,没有的话查询二级缓存,最后查询数据库;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库。


4> 简单总结


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


 十一. Hibernate:Query的list()和iterator()的区别:
Query中有list()与iterator()方法,两者的差别在于list()方法在读取数据时,并不会利用到快取,而是直接再向数据库查询,而iterator()则将读取到的数据写到快取,并于读取时再次利用。
来看看下面的程序:


Session session = sessionFactory.openSession();       
Query query = session.createQuery("from User");
List users = query.list();
users = query.list();
session.close();
这个程序片段会使用两次SQL来查询数据库:


Hibernate: select user0_.id as id, user0_.name as name0_, user0_.age as age0_ from user user0_
Hibernate: select user0_.id as id, user0_.name as name0_, user0_.age as age0_ from user user0_
如果在Session关闭之前,要再将所有数据在取出,可以使用iterator()方法,例如:


Session session = sessionFactory.openSession();
Query query = session.createQuery("from User");
Iterator users = query.iterate();
users = query.iterate();
session.close();
这个程序片段会使用一次SQL向数据库查询,第二次则直接从快取中取得数据:


Hibernate: select user0_.id as col_0_0_ from user user0_
由于使用iterator()方法时会使用到Session level快取,所以在查询大量数据时,会耗用大量的内存,必要时可以使用Session的evict()或clear()方法来清除快取。


 
十二.  Hibernate中实体对象的三种管理状态
在Hibernate中最核心的概念就是 对实体对象(POJO/Domain Object)的状态管理。
实体对象的状态有三种:Transient(瞬时状态)、Persistent(持久状态) 、Detached (脱管状态)


Transient(瞬时状态):也就是未被持久化的VO(value object)是由JVM维护其生命周期。如下代码:


User user=new User();
User.setName("ZCH");//此时 user处于 Transient状态,由JVM管理
Persistent(持久状态):此时实体对象处于由hibernate管理的状态,并且与数据库表记录同步。如下代码:


Transaction tx=session.beginTransaction();
session.save(user);//此时 user处于 Persistent状态,由hibernate管理
Detached(脱管状态):也就是曾被持久化过,但现在和Session已经detached了,以VO的身份在运行 。
这种和Session已经detached(分离)的PO还能够进入另一个Session,继续进行PO状态管理,此时它就成为PO的第二种状态了。这种PO实际上是跨了Session进行了状态维护的。如下代码:


tx.commit();//事务提交之后 数据库中插入name="ZCH"记录
session.close();//此时的user已经处于Detached状态,因为与其关联的session已经关闭


十三.  Hibernate的缓存机制
1> 什么是缓存?
    缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高应用程序的运行性能.


2>缓存在Hibernate中的应用
    Hibernate在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升.


3> Hibernate缓存分类及原理:
  一级缓存: Session缓存,默认带有且不能卸载。


  二级缓存:SessionFactory缓存,它分为内置缓存和外置缓存.内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定义SQL语句等),对于应用程序来说,它是只读的.外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备.


  二级缓存是由sessionFactory控制的进程级缓存。是全局共享的缓存,凡是会调用二级缓存的查询方法 都会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方法永远是从数据库中获取数据,不会从二级缓存中获取数据,即便其中有其所需要的数据也是如此。


  查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低的。


4> Hibernate的缓存范围


  Hibernate的一级缓存和二级缓存都均位于持久层,且均用于存放数据库数据的副本,最大的区别就是缓存的范围各不一样.


  缓存的范围分为3类:


  事务范围:事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围.


  应用范围:应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围.


  集群范围:在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致,缓存中的数据通常采用对象的松散数据形式.


5> Hibernate的缓存管理


  一级缓存的管理:
    evit(Object obj): 将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象.
    clear(): 将一级缓存中的所有持久化对象清除,释放其占用的内存资源
    contains(Object obj): 判断指定的对象是否存在于一级缓存中.
    flush(): 刷新一级缓存区的内容,使之与数据库数据保持同步.


  二级缓存的管理:
    evict(Class arg0, Serializable arg1): 将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源.


    sessionFactory.evict(Customer.class, new Integer(1));
  evict(Class arg0): 将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源.


    sessionFactory.evict(Customer.class);
  evictCollection(String arg0):将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源.


    sessionFactory.evictCollection("Customer.orders");
6> Hibernate二级缓存的配置
    Hibernate的二级缓存功能是靠配置二级缓存插件来实现的,Hibernate为了集成这些插件,Hibernate提供了org.hibernate.cache.CacheProvider借口,它充当缓存插件与Hibernate之间的适配器 .
    常用的二级缓存插件:
        EHCache org.hibernate.cache.EhCacheProvider
        OSCache org.hibernate.cache.OSCacheProvider
        SwarmCahe org.hibernate.cache.SwarmCacheProvider
        JBossCache org.hibernate.cache.TreeCacheProvider


  EHCache的配置实现:
    hibernate.cfg.xml配置文件内容如下:


<hibernate-configuration>
   <session-factory>
      <!-- 设置二级缓存插件EHCache的Provider类-->
      <property name="hibernate.cache.provider_class">
         org.hibernate.cache.EhCacheProvider
      </property>
      <!-- 启动"查询缓存" -->
      <property name="hibernate.cache.use_query_cache">
         true
      </property>
   </session-factory>
 </hibernate-configuration>
    ehcache.xml 配置文件内容如下:


<ehcache>
  <!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 --> 

 

 

   hibernate.cfg.xml配置文件内容如下:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.-->
<hibernate-configuration>
    <session-factory>
        <!-- 方言 -->
  <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
  <!-- 数据库连接 -->
  <property name="connection.url">jdbc:mysql://localhost:3306/db_database16</property>
  <!-- 数据库连接用户名 -->
  <property name="connection.username">root</property>
  <!-- 数据库连接密码 -->
  <property name="connection.password">123456</property>
  <!-- 数据库驱动 -->
  <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  <!-- 打印SQL语句 -->
  <property name="show_sql">true</property>
  <!-- 自动建表 -->
  <property name="hbm2ddl.auto">update</property>
  <!-- 映射文件 -->  
  <mapping resource="com/lyq/model/Message.hbm.xml"/>
  <mapping resource="com/lyq/model/Revert.hbm.xml"/>
  <mapping resource="com/lyq/model/User.hbm.xml"/>     
    </session-factory>
</hibernate-configuration>

 

 


    ***.hbm.xml 配置文件内容如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="com.lyq.model">
 <class name="Message" table="tb_message">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="title" not-null="true"/>
  <property name="content" type="text" not-null="true"/>
  <property name="createTime"/>
  <!-- 映射与用户的多对一关系 -->
  <many-to-one name="user" class="User" lazy="false">
   <column name="userid" />
  </many-to-one>
  <!-- 映射与回复的一对一关系 -->
  <many-to-one name="revert" class="Revert" unique="true" cascade="all" lazy="false"/>
 </class>
</hibernate-mapping>