hibernate

把映射文件加进去,
hibernate初始化的时候用dom4j做分析器,来分析配置文件。
每加一个类,都把映射文件加载了。
Configuration
里面的validate方法里面进行一系列验证,
像有没有这个字段,环境配置对不对。
Dialect这个类,处理了数据库方言,
方言:这个数据库的方言只有这个数据库可以用,其它的数据库用不了。
     把各个数据库不同的语法,全部定义好。
像分页技术,数据库不同,实现分页的方法不同。
使用到了模板模式,
cglib(Code Generation Library):
hibernate用到cglib动态生成类,它生成的类是二进制的,不用编译。
反射,Proxy和元数据是java最强的三个特征。
Proxy可以看作是微型的AOP,可惜Proxy必须基于接口。
因此Spring的做法,基于接口的用Proxy,否则就用cglib.
实现MethodInterceptor,可以对方法进行拦截。
hibernate3.3以后用到了javassist
动态生成字节码,

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


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


3. 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();
4. Hibernate 的5个核心接口及作用
Configuration 接口:配置Hibernate,根据其启动hibernate,创建SessionFactory 对象;


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


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


Transaction 接口:管理事务;


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


5. 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检索必须检索对象的所有属性.


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


7.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(); 
        …… 
    } 
}
8. Hibernate如何实现数据批量删除或更新?
String sql = "delete from Person where name = ?";
Query query = session.createQuery(sql);//SQL语句”update”或”delete”
query.setString(0,"maozedong");
query.executeUpdate();
9. 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:直接返回一个对象 




10.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。


11.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()方法来清除快取。


 
12. 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已经关闭
13. 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对象处于缓存状态的最多秒数 --> 
  <diskStore path="java.io.tmpdir"/> 
    <defaultCache maxElementsInMemory="10000" eternal="false"  timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/> 
</ehcache>
    ***.hbm.xml 配置文件内容如下: 


<?xml version="1.0" encoding='UTF-8'?>&nbsp;
<\!DOCTYPE hibernate-mapping PUBLIC&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "-//Hibernate/Hibernate Mapping DTD 3.0//EN"&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "[http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd|http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd]" >&nbsp;&nbsp;&nbsp;
<hibernate-mapping>&nbsp;&nbsp;
&nbsp;&nbsp; <class>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\!-\- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <cache usage="read-write"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; </class>&nbsp;&nbsp;
</hibernate-mapping>
14. Hibernate性能优化
有很多人认为Hibernate天生效率比较低,确实,在普遍情况下,需要将执行转换为SQL语句的Hibernate的效率低于直接JDBC存取,然而,在经过比较好的性能优化之后,Hibernate的性能还是让人相当满意的,特别是应用二级缓存之后,甚至可以获得比较不使用缓存的JDBC更好的性能,下面介绍一些通常的Hibernate的优化策略:


1> 抓取优化: 抓取是指Hibernate如何在关联关系之间进行导航的时候,Hibernate如何获取关联对象的策略,其主要定义了两个方面:如何抓取和何时抓取


①如何抓取。
Hibernate3主要有两种种抓取方式,分别应用于对象关联实例(many-to-one、one-to-one)和对象关联集合(set、map等),总共是四种变种
JOIN抓取: 通过在SELECT语句中使用OUTER JOIN来获得对象的关联实例或者关联集合)
SELECT抓取: 另外发送一条SELECT语句来抓取当前对象的关联实体和集合
通过开发经验总结,此处对性能的优化是比较有限的,并不值得过多关注
例:
A.应用于对象关联实例(默认是false)
<many-to-one name=".." outer-join="true/false/auto" .../> 
B.应用于对象关联集合(默认是auto)
<set name=".." fetch="join/select" ... >
....
</set>


②何时抓取
主要分为延迟加载和立即抓取,默认的情况下Hibernate3对对象关联实采用延迟加载,普通属性采用立即抓取,通过延迟加载和采用适当的抓取粒度,与不采用优化相比往往可以将性能提升数倍
立即抓取:当抓取宿主对象时,同时抓取其关联对象和关联集以及属性
延迟加载:当抓取宿主对象时,并不抓取其关联对象,而是当对其对象进行调用时才加载
例:
A.应用于对象关联实例(默认是延迟加载)
<many-to-one name=".." lazy="true/false" .../> 
B.应用于对象关联集合(默认是延迟加载)
<set name=".." lazy="true/false" ... >
....
</set>
对于延迟加载,需要注意的时,对延迟对象的使用必须在Session关闭之前进行,Hibernate的LazyInitalizationException往往就是由于在Session的生命期外使用了延迟加载的对象。当我们进行Web开发时,可以使用OpenSessionInView模式,当请求开始时打开session,当请求响应结束时才关闭session,不过,在使用OpenSessionInView模式时,需要注意如果响应时间比较长(业务比较复杂或者客户端是低速网络),将Session资源(也就是数据库的连接)占用太久的话可以会导致资源耗尽


③抓取粒度
抓取粒度指的是对象在关联关系之间被导航时一次预先加载的数量,Hibernate程序的性能比较差往往就在于没有对抓取粒度仔细考虑,当加载一个列表并在列表中的每个对象中对其关联进行导航时,往往导致N+1条SQL语句查询。
例:
A.应用于对象关联实例(默认为1),注意,对对象关联实例的设置是在被关联的对象之上的,譬如
class User


Unknown macro: { Group g; }
那么抓取粒度应该在Group的配置文件之上,见下
<class name="Group" table="group" batch-size="..">
...
</class>
对该值并没有一个约定俗成的值,根据情况而定,如果被关联表数据比较少,则可以设置地小一些,3-20,如果比较大则可以设到30-50,注意的时候,并不是越多越好,当其值超过50之后,对性能并没有多大改善但却无谓地消耗内存
假设有如下例子:
List<User> users = query.list();
如果有20个User,并对这20个User及其Group进行遍历,如果不设置batch-size(即batch-size="1"),则在最糟糕的情况
下,需要1 + 20条SQL语句,如果设置batch-size="10",则最好的情况下只需要1 + 2条SQL语句
B.应用于对象关联集合(默认为1)
<set name=".." batch-size="" ... >
....
</set>


2> 二级缓存
Hibernate对数据的缓存包括两个级:一级缓存,在Session的级别上进行,主要是对象缓存,以其id为键保存对象,在Session的生命期间存在;二级缓存,在SessionFactory的级别上进行,有对象缓存和查询缓存,查询缓存以查询条件为键保存查询结果,在SessionFactory的生命期间存在。默认地,Hibernate只启用一级缓存,通过正确地使用二级缓存,往往可以获得意想不到的性能。
①对象缓存:
当抓取一个对象之后,Hiberate将其以id为键缓存起来,当下次碰到抓取id相同的对象时,可以使用如下配置
方法1:在缓存对象上配置
<class ...>
<cache useage="read-only/write/...." regions="group" />
</class>
useage表示使用什么类型的缓存,譬如只读缓存、读写缓存等等(具体参见Hibernate参考指南),值得注意的时,有部分缓存在Hibernate的实现中不支持读写缓存,譬如JBossCache在Hibernate的实现中只是一种只读缓存,具体缓存实现对缓存类型的支持情况,可以参见org.hibernate.cache包
regions表示缓存分块,大部分的缓存实现往往对缓存进行分块,该部分是可选的,详细参见各缓存实现
方法2:在hibernate.cfg.xml中配置
<cache class=".." useage=".." regions=".."/>
建议使用第二种更好,可以统一管理


②查询缓存
查询时候将查询结果以查询条件为键保存起来,需要配置如下
A.在hibernate.cfg.xml中配置(启用查询缓存)
<property name="hibernate.cache.use_query_cache">true</property> (前面的属性名可参见常量
org.hibernate.cfg.Enviroment.USE_QUERY_CACHE)
B.程序
query.setCacheable(true);
query.setCacheRegions(...);
需要注意的是,查询缓存与对象缓存要结合更有效,因为查询缓存仅缓存查询结果列表的主键数据
一般情况下在开发中,对一些比较稳定而又被频繁引用的数据,譬如数据字典之类的,将其进行二级缓存,对一些查询条件和查询数据变化不频繁而又常常被使用的查询,将其进行二级缓存。由于二级缓存是放在内存中,而且Hibernate的缓存不是弱引用缓存(WeekReference),所以注意不要将大块的数据放入其中,否则可能会被内存造成比较大的压力。


3> 批量数据操作
当进行大批量数据操作(几万甚至几十几百万)时,需要注意两点,一,批量提交,二,及时清除不需要的一级缓存数据
①所谓的批量提交,就是不要频繁使用session的flush,每一次进行flush,Hibernate将PO数据于数据库进行同步,对于海量级数据操作来说是性能灾难(同时提交几千条数据和提交一条数据flush一次性能差别可能会是几十倍的差异)。一般将数据操作放在事务中,当事务提交时Hibernate自动帮你进行flush操作。
②及时清除不需要的一级缓存数据:由于Hibernate默认采用一级缓存,而在session的生命期间,所有数据抓取之后会放入一级缓存中,而当数据规模比较庞大时,抓取到内存中的数据会让内存压力非常大,一般分批操作数据,被一次操作之后将一级缓存清除,譬如
session.clear(User.class)


4> 杂项
dynamic-insert,dynamic-update,动态插入和动态更新,指的是让Hibernate插入数据时仅插入非空数据,当修改数据时只修改变化的数据,譬如对于 
class User


Unknown macro: { id username password }
如果u.id=1, u.username="ayufox",u.password=null,那么为update user set password='11' where d = 1
设置是在class的映射文件中,如下如果不设置动态插入,则其sql语句是insert into users(id, username, password) values (1, 'ayufox', '),如果设置则其sql语句是insert into users(username) valeus('ayufox')
在如上的情况下,如果修改u.password='11',那么如果不设置动态更新,则sql语句为update users set username='ayufox', password='11' where id = 1,如果设置则
<class name="User" table="users" dynamic=insert="true/false" dynamic-update="true/false" ...>
</class>
  该设置对性能的提升比较有限
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值