posts - 66,  comments - 11,  trackbacks - 0
package com.hibernate.higherApplication;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Expression;

public class DurationOperator extends TestCase {
    
private SessionFactory sessionFactory = null;
    
private Session session = null;
    
/**
     * 初始化资源
     
*/
    
protected void setUp() throws Exception {
        
try {
            
//加载类路径下的hibernate.cfg.xml文件
            Configuration config = new Configuration().configure();
            
//创建sessionFactory对象
            sessionFactory = config.buildSessionFactory();
            
//创建session
            session = sessionFactory.openSession();
        } 
catch (HibernateException e) {
            e.printStackTrace();
        }
    }
    
/**
     * load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。
     * 区别在于:
     * 1、如果未发现符合条件的记录,get方法返回null,而load方法抛出一个ObjectNotFoundException
     * 2、load方法可以返回实体的代理类实例,而get方法永远直接返回实体类。
     * 3、load方法可以充分利用内部缓存和二级缓存中的现有数据,而get方法则仅仅在内部缓存中进行数据查找,如果
     * 没有发现数据,将越过二级缓存,直接调用SQL完成数据读取。
     *
     
*/
    
public void loadOrGetData(){
        TUser user 
= (TUser)session.load(TUser.class,new Integer(1));
    }
    
/**
     * 查询性能往往是一系统性能表现的一个重要方面。
     * query.list方法通过一条select SQL实现了查询操作,而iterate方法,则执行了3次selectSQL,第一次获取了所有符合条件的记录
     * 的id,之后,在根据各个id从库表中读取对应的哦记录,这是一个典型的N+1次查询问题。
     * 
     * 我们进行query.list数据查询时,即使缓存中已经有一些符合条件的实体对象存在,我们也无法保证这些数据就是库表中所有符合条件的数据。假设
     * 第一次查询条件是age>25,随即缓存中就包括了所有age>25的user数据;第二次查询条件为age>20,此时缓存中虽然包含了满足age>25d的
     * 数据,但这些并不是满足条件age>20的全部数据
     * 因此,query.list方法还是需要执行一次select sql以保证查询结果的完整性(iterate方法通过首先查询获取所有符合条件记录的id,以此保证
     * 查询结果的完整性)。
     * 因此,query.list方法实际上无法利用缓存,它对缓存只写不读。而iterate方法则可以充分发挥缓存带来的优势,如果目标数据只读或者读取相对
     * 较为频繁,通过这种机制可以大大减少性能上的损耗。
     
*/
    
public void queryForList(){
        String hql 
= "from TUser where age>?";
        Query query 
= session.createQuery(hql);
        query.setInteger(
1,1);
        
        List list 
= query.list();
        
        
for(int i=0;i<list.size();i++){
            TUser user 
= (TUser)list.get(i);
            System.out.println(
"User age:"+user.getAge());
        }
    }
    
public void queryForIterate(){
        String hql 
= "from TUser where age>?";
        Query query 
= session.createQuery(hql);
        query.setInteger(
1,1);
        
        Iterator it 
= query.iterate();
        
        
while(it.hasNext()){
            TUser user 
= (TUser)it.next();
            System.out.println(
"User age:"+user.getAge());
        }
    }
    
/**
     * 大数据量的批量读取(10W条)
     * 解决方案:结合iterate方法和evict方法逐条对记录进行处理,将内存消耗保持在可以接受的范围之内。
     * 在实际开发中,对于大批量数据处理,还是推荐采用SQL或存储过程实现,以获得较高的性能,并保证系统平滑运行。
     
*/
    
public void bigDataRead(){
        String hql 
= "from TUser where age>?";
        Query query 
= session.createQuery(hql);
        query.setInteger(
"age"1);
        Iterator it 
= query.iterate();
        
        
while(it.hasNext()){
            TUser user 
= (TUser)it.next();
            
//将对象从一级缓存中移除
            session.evict(user);
            
//二级缓存可以设定最大数据缓存数量,达到峰值时会自动对缓存中的较老数据进行废除,但是我们这里还是通过
            
//编码指定将对象从二级缓存中移除,这有助保持缓存的数据有效性。
            sessionFactory.evict(TUser.class,user.getId());
        }
    }
    
/**
     * Query Cache弥补了find方法的不足,QueryCache中缓存的SQL及其结果及并非永远存在,当Hibernate发现此SQL对应的库表发生变动,
     * 会自动将Query Cache中对应表的SQL缓存废除。因此Query Cache只在特定的情况下产生作用:
     * 1、完全相同的select SQL重复执行。
     * 2、在2次查询之间,此select SQL对应的库表没有发生过改变。
     
*/
    
public void queryForQueryCache(){
        String hql 
= "from TUser where age>?";
        Query query 
= session.createQuery(hql);
        query.setInteger(
11);
        
//除了在这里设置QueryCache外,还要在hibernate.cfg.xml中进行设置
        
//<property name="hibernate.cache.use_query_cache">true</property>
        query.setCacheable(true);
        List userList 
= query.list();
    }
    
/**
     * 所谓延迟加载,就是在需要数据的时候,才真正执行数据加载操作。
     * 延迟加载实现主要针对:
     * 1、实体对象:通过class的lazy属性,我们可以打开实体对象的延迟加载功能。
     * 2、集合
     
*/
    
public void queryForEntityLazy(){
        Criteria criteria 
= session.createCriteria(TUser.class);
        criteria.add(Expression.eq(
"name","Erica"));
        
        List userList 
= criteria.list();
        TUser user 
= (TUser)userList.get(0);
        
//虽然使用了延迟加载,但是我们可以通过hibernate的初始化方法进行强制加载,这样即使session关闭之后,关联的对象仍让可以使用
        Hibernate.initialize(user.getAddresses());
        
        System.out.println(
"User name=>"+user.getAge());
        
        Set hset 
=user.getAddresses();
        TAddresses addr 
= (TAddresses)hset.toArray()[0];
        System.out.println(addr.getAddress());
        
        session.close();
    }
    
/**
     * 关闭资源
     
*/
    
protected void tearDown() throws Exception {
        
try{
            session.close();
        }
catch(HibernateException e){
            e.printStackTrace();
        }
    }

}
posted @ 2010-01-02 15:27 王永庆 阅读(354) | 评论 (0)编辑 收藏
  基于Java的缓存实现,最简单的方式莫过于对集合类数据类型进行封装。Hibernate提供了基于Hashtable的缓存实现机制,不过,由于其性能和功能上的局限,仅供开发调试中使用。同时,Hibernate还提供了面向第三方缓存实现的接口,如:
HashTable--------------------------------net.sf.hibernate.cache.HashtableCacheProvider
1、JSC
2、EHCache->默认的二级Cache实现。--------net.sf.encache.hibernate.Provider
3、OSCache-------------------------------net.sf.hibernate.cache.OSCacheProvider
4、JBoss Cache->分布式缓存---------------net.sf.hibernate.cache.TreeCacheProvider
5、SwarmCache----------------------------net.sf.hibernate.cache.SwarmCacheProvider
相对于JSC而言,EHCache更加稳定,并具备更好的混存调度性能,其缺陷是目前还无法做到分布式缓存。
首先设置hibernate.cfg.xml然后设置ehcache.xml最后设置缓存策略。

  缓存同步策略决定了数据对象在缓存中的存取规则。为了使得缓存调度遵循正确的应用级事物隔离机制,我们必须为每个实体类指定相应的缓存同步策略。Hibernate提供4种内置的缓存同步策略:
1、read-only:只读。对于不会发生改变的数据,可使用只读型缓存。
2、nonstrict-read-write:如果程序对并发访问下的数据同步要求不是非常严格,且数据更新操作频率较低,可以采用本选项。
3、read-write:严格可读写缓存。
4、transactional:事务型缓存,必须运行在JTA事物环境中。

  JDBC事物由Connection管理,也就是说,事务管理实际上是在JDBC Connection中实现。事务周期限于Connection的生命周期之类。同样,对于基于JDBC Transaction的Hibernate事务管理机制而言,事物管理在Session所以托的JDBCConnection中实现,事务周期限于Session的生命周期。
  JTA事物管理则由JTA容器实现,JTA容器对当前加入事物的众多Connection进行调度,实现其事务性要求。JTA的事物周期可横跨多个JDBC Connectin生命周期。同样对于基于JTA事务的Hibernate而言,JTA事物横跨多个Session.

  Hibernate支持2种锁机制:即通常所说的悲观锁和乐观锁。
  悲观锁的实现,往往依靠数据库提供的锁机制。典型的悲观锁调用:
  select * from account where name=="Erica" for update
package com.hibernate.higherApplication;

import java.util.List;

import junit.framework.TestCase;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Expression;

public class LockOperator extends TestCase {
    
private Session session = null;
    
/**
     * 初始化资源
     
*/
    
protected void setUp() throws Exception {
        
try {
            
//加载类路径下的hibernate.cfg.xml文件
            Configuration config = new Configuration().configure();
            
//创建sessionFactory对象
            SessionFactory sessionFactory = config.buildSessionFactory();
            
//创建session
            session = sessionFactory.openSession();
        } 
catch (HibernateException e) {
            e.printStackTrace();
        }        
    }
    
/**
     * 悲观锁
     * Hibernate的加锁模式有:
     * 1、LockMode.NONE:无锁机制
     * 2、LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取
     * 3、LockMode.READ:Hibernate在读取记录的时候会自动获取
     * 上述3种锁机制为了保证update过程中对象不会被外界修改,在目标对象上加锁,与数据库无关
     * 4、LockMode.UPGRADE:利用数据库的for update子句加锁
     * 5、LockMode.UPGRADE_NOWAIT:oracle的特定实现
     * 注意:只有在查询开始之前设定加锁,才会真正通过数据库的锁机制进行加锁处理。
     
*/
    
public void addPessimismLock(){
        String hqlStr 
= "from TUser as user where user.name='Erica'";
        Query query 
= session.createQuery(hqlStr);
        query.setLockMode(
"user",LockMode.UPGRADE);//多所有返回的user对象加锁
        List userList = query.list();//执行查询
    }
    
/**
     * 乐观锁
     * 数据版本:即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个version字段来实现。
     * 读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1.此时,将提交数据的版本数据与数据库对应记录的当前版本信息
     * 进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
     * 
     * Hibernate在其数据访问引擎中内置了乐观锁实现。如果不考虑外部系统对数据库的更新操作,利用Hibernate提供的透明化乐观锁
     * 实现,将大大提升我们的生产力。见配置文件T_USER.hbm.xml
     * 乐观锁机制避免了长事务中的数据加锁开销,大大提升了大并发量下的系统整体性能表象。
     *
     
*/
    
public void addOptimismLock(){
        Criteria criteria 
= session.createCriteria(TUser.class);
        criteria.add(Expression.eq(
"name","Erica"));
        
        List userList 
= criteria.list();
        TUser user 
= (TUser)userList.get(0);
        
        Transaction tx 
= session.beginTransaction();
        user.setVersion(
1);
        tx.commit();
    }
    
/**
     * 关闭资源
     
*/
    
protected void tearDown() throws Exception {
        
try{
            session.close();
        }
catch(HibernateException e){
            e.printStackTrace();
        }
    }
    
}

<?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>
    
<!-- 
        none:无乐观锁
        version:通过版本机制实现乐观锁
        dirty:通过检查发生变动过的属性实现乐观锁
        all通过检查所有属性实现乐观锁
     
-->
    
<class
        
name="org.hibernate.sample.TUSER"
        table
="t_user"
        dynamic-update
="true"
        dynamic-insert
="true"
        optimistic-lock
="version"
        lazy
="true"
        
>
        
<id
        
name="id"
        column
="id"
        type
="java.lang.Integer"
        
>
            
<generator class="native">
            
</generator>
        
</id>
        
<version name="version" column="version" type="java.lang.Integer">
        
</version>
        
<set name="addresses"
             table
="t_address"
             lazy
="true"
             inverse
="false"
             cascade
="all"
        
>
            
<key
                
column="user_id"
            
>
            
</key>
            
<one-to-many class=""/>
        
</set>
    
</class>
</hibernate-mapping>


posted @ 2010-01-02 15:25 王永庆 阅读(552) | 评论 (0)编辑 收藏
    实体对象,特指Hibernate O/R映射关系中的域对象。实体对象生命周期中的3种状态
    1、Transient(自由状态):所谓Transient,即实体对象在内存中的自由存在,它与数据库中的记录无关。
    2、Persistent(持久状态):即实体对象处于由Hibernate框架所管理的状态。
    3、Detached(游离状态):处于Persistent状态的对象,其对应的Session实例关闭之后,那么,此对象就处于"Detached"状态。
    Transient状态的user对象与库表的数据缺乏对应关系,而Detached状态的user对象,却在库表中存在对应的记录,只不过由于Detached对象脱离了session这个数据操作平台,其状态的变化无法更新到库表中的对应记录。
    处于Transient和Detached状态的对象统称为值对象(VO),而处于Persistent状态的对象称为持久对象(PO).这是站在实体对象是否被纳入Hibernate实体管理容器的立场加以区分的,非管理的实体对象统称为VO,而被管理的实体对象称为PO.
VO与PO的主要区别在于:
1、VO是相对独立的实体对象,处于非管理状态。
2、PO是由Hibernate纳入其实体管理容器的对象,它代表了与数据库中某条记录对应的Hibernate实体,PO的变化在事务提交时将反映到实际数据库中
3、如果一个PO与其对应的Session实例分离,那么此时,它又会变成一个VO。

    不覆盖equals/hashCode方法的情况下我们要面对的问题:实体对象的跨session识别。解决办法一个是实现所谓的值比对,即在equals/hashCode方法中,对实体类的所有属性值进行比对.除了值比对,还有另外一种基于业务逻辑的对象判定方式业务关键信息判定。

    tx.commint();方法中会调用session.flush()方法,在flush()方法中会执行2个主要任务
1、flushEverything();//刷新所有数据
2、execute(0);//执行数据库SQL完成持久化动作。

    数据缓存:在特定硬件基础上缓存往往是提升系统性能的关键因素。缓存是数据库数据在内存中的临时容器,它包含了库表数据在内存中的临时拷贝,位于数据库与数据访问层之间。ORM在进行数据读取时,会根据其缓存管理策略,首先在缓存中查询,如果在缓存中发现所需数据,则直接以此数据作为查询结果加以利用,从而避免了数据库调用的性能开销。
    相对内存操作而言,数据库调用是一个代价高昂的过程,对于典型企业及应用结构,数据库往往与应用服务器位于不同的物理服务器,这也就意味着每次数据库访问都是一次远程调用,Socket的创建与销毁,数据的打包拆包,数据库执行查询命令,网络传输上的延时,这些消耗都给系统整体性能造成了严重影响。
    ORM的数据缓存应包含如下几个层次:
1、事务级缓存:事务级缓存是基于Session生命周期实现的,每个Session会在内部维持一个数据缓存,此缓存随着Session的创建而存在,因此也成为Session Level Cache(内部缓存)
2、应用级/进程级缓存:在某个应用中,或者应用中某个独立数据访问子集中的共享缓存。此缓存可由多个事物共享。在Hibernate中,应用级缓存在SessinFactory层实现,所有由此SessionFactory创建的Session实例共享此缓存。多实例并发运行的环境要特别小心进程级缓存的调用。
3、分布式缓存:分布式缓存由多个应用级缓存实例组成集群,通过某种远程机制实现各个缓存实例间的数据同步,任何一个实例的数据修改操作,将导致整个集群间的数据状态同步。由于多个实例间的数据同步机制,每个缓存实例发生的变动都会复制到其余所有节点中,这样的远程同步开销不可忽视。

    Hibernate数据缓存分为2个层次,1、内部缓存2、二级缓存hibernate中,缓存将在以下情况中发挥作用:
1、通过ID加载数据时
这包括了根据id查询数据的Session.load方法,以及Session.ierate等批量查询方法
2、延迟加载

    Session在进行数据查询操作时,会首先在自身内部的一级缓存中进行查找,如果一级缓存未能命中,则将在二级缓存中查询,如果二级缓存命中,则以此数据作为结果返回。
    如果数据满足以下条件,则可将其纳入缓存管理
1、数据不会被第三方应用修改
2、数据大小在可接受的范围之内
3、数据更新频率较低
4、同一数据可能会被系统频繁引用
5、非关键数据(关键数据,如金融账户数据)
Hibernate本身并未提供二级缓存的产品化实现(只是提供了一个基于Hashtable的简单缓存以供调试),而是为众多的第三方缓存组件提供了接入接口,我们可以根据实际情况选择不同的缓存实现版本。

   
posted @ 2009-12-22 15:01 王永庆 阅读(209) | 评论 (0)编辑 收藏
<2009年12月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(1)

随笔分类

随笔档案

关注blogs

搜索

  •  

最新评论

阅读排行榜

评论排行榜