Hibernate 3.6.10.Final ²Î¿¼ÊÖ²á ÖÐÎÄ°æ

Hibernate

Hibernate.org Community Documentation

  • 连接抓取(Join fetching):Hibernate 通过在 SELECT 语句使用 OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。

  • 查询抓取(Select fetching):另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定 lazy="false" 禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条 select 语句。

  • 子查询抓取(Subselect fetching):另外发送一条 SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定 lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条 select 语句。

  • 批量抓取(Batch fetching):对查询抓取的优化方案,通过指定一个主键或外键列表,Hibernate 使用单条 SELECT 语句获取一批对象实例或集合。

  • Immediate fetching,立即抓取:当宿主被加载时,关联、集合或属性被立即抓取。

  • Lazy collection fetching,延迟集合抓取:直到应用程序对集合进行了一次操作时,集合才被抓取(对集合而言这是默认行为)。

  • "Extra-lazy" collection fetching,"Extra-lazy" 集合抓取:对集合类中的每个元素而言,都是直到需要时才去访问数据库。除非绝对必要,Hibernate 不会试图去把整个集合都抓取到内存里来(适用于非常大的集合)。

  • Proxy fetching,代理抓取:对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行 get 操作时才抓取。

  • "No-proxy" fetching,非代理抓取:对返回单值的关联而言,当实例变量被访问的时候进行抓取。与上面的代理抓取相比,这种方法没有那么“延迟”得厉害(就算只访问标识符,也会导致关联抓取)但是更加透明,因为对应用程序来说,不再看到 proxy。这种方法需要在编译期间进行字节码增强操作,因此很少需要用到。

  • Lazy attribute fetching,属性延迟加载:对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取。需要编译期字节码强化,因此这一方法很少是必要的。

= sessions.openSession();
Transaction tx = s.beginTransaction();

            
User u = (User) s.createQuery("from User u where u.name=:userName")
    .setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();
tx.commit();
s.close();
Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

<set name="permissions"
            fetch="join">
    <key column="userId"/>
    <one-to-many class="Permission"/>
</set

<many-to-one name="mother" class="Cat" fetch="join"/>
  • 通过 get()load() 方法取得数据。

  • 只有在关联之间进行导航时,才会隐式的取得数据。

  • 条件查询

  • 使用了 subselect 抓取的 HQL 查询

User user = (User) session.createCriteria(User.class)

                .setFetchMode("permissions", FetchMode.JOIN)
                .add( Restrictions.idEq(userId) )
                .uniqueResult();

<class name="Cat" proxy="Cat">
    ......
    <subclass name="DomesticCat">
        .....
    </subclass>
</class>
Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)

if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
    DomesticCat dc = (DomesticCat) cat;       // Error!
    ....
}
Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy

DomesticCat dc = 
        (DomesticCat) session.load(DomesticCat.class, id);  // acquire new DomesticCat proxy!
System.out.println(cat==dc);                            // false
cat.setWeight(11.0);  // hit the db to initialize the proxy

System.out.println( dc.getWeight() );  // 11.0

<class name="CatImpl" proxy="Cat">
    ......
    <subclass name="DomesticCatImpl" proxy="DomesticCat">
        .....
    </subclass>
</class>
Cat cat = (Cat) session.load(CatImpl.class, catid);

Iterator iter = session.createQuery("from CatImpl as cat where cat.name='fritz'").iterate();
Cat fritz = (Cat) iter.next();

注意

list() 通常不返回代理。

  • equals() 方法,如果持久类没有重载 equals() 方法。

  • hashCode():如果持久类没有重载 hashCode() 方法。

  • 标志符的 getter 方法。

  • 在一个基于 Web 的应用中,可以利用 servlet 过滤器(filter),在用户请求(request)结束、页面生成 结束时关闭 Session(这里使用了在展示层保持打开 Session 模式(Open Session in View)),当然,这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前,乃至在生成界面过程中发生异常的情况下,正确关闭 Session 和结束事务将是非常重要的, 请参见 Hibernate wiki 上的 "Open Session in View" 模式,你可以找到示例。

  • 在一个拥有单独业务层的应用中,业务层必须在返回之前,为 web 层“准备”好其所需的数据集合。这就意味着 业务层应该载入所有表现层/web 层所需的数据,并将这些已实例化完毕的数据返回。通常,应用程序应该为 web 层所需的每个集合调用 Hibernate.initialize()(这个调用必须发生咱 session 关闭之前);或者使用带有 FETCH 从句,或 FetchMode.JOIN 的 Hibernate 查询,事先取得所有的数据集合。如果你在应用中使用了 Command 模式,代替 Session Facade,那么这项任务将会变得简单的多。

  • 你也可以通过 merge()lock() 方法,在访问未实例化的集合(或代理)之前,为先前载入的对象绑定一个新的 Session。显然,Hibernate 将不会,也不应该自动完成这些任务,因为这将引入一个特殊的事务语义。

          
          (
          
           
          
          (
          
          Integer
          
          )
          
           s
          
          .
          
          createFilter
          
          (
          
           collection
          
          ,
          
           
          
          "select count(*)"
          
           
          
          ).
          
          list
          
          ().
          
          get
          
          (
          
          0
          
          )
          
           
          
          ).
          
          intValue
          
          ()
        
          
          s
          
          .
          
          createFilter
          
          (
          
           lazyCollection
          
          ,
          
           
          
          ""
          
          ).
          
          setFirstResult
          
          (
          
          0
          
          ).
          
          setMaxResults
          
          (
          
          10
          
          ).
          
          list
          
          ();
        

<class name="Person" batch-size="10">...</class>

<class name="Person">
    <set name="cats" batch-size="3">
        ...
    </set>
</class>

@Entity
@FetchProfile(name = "customer-with-orders", fetchOverrides = {
   @FetchProfile.FetchOverride(entity = Customer.class, association = "orders", mode = FetchMode.JOIN)
})
public class Customer {
   @Id
   @GeneratedValue
   private long id;

   private String name;

   private long customerNumber;

   @OneToMany
   private Set<Order> orders;

   // standard getter/setter
   ...
}


<hibernate-mapping>
    <class name="Customer">
        ...
        <set name="orders" inverse="true">
            <key column="cust_id"/>
            <one-to-many class="Order"/>
        </set>
    </class>
    <class name="Order">
        ...
    </class>
    <fetch-profile name="customer-with-orders">
        <fetch entity="Customer" association="orders" style="join"/>
    </fetch-profile>
</hibernate-mapping>


<hibernate-mapping>
    <class name="Customer">
        ...
        <set name="orders" inverse="true">
            <key column="cust_id"/>
            <one-to-many class="Order"/>
        </set>
        <fetch-profile name="customer-with-orders">
            <fetch association="orders" style="join"/>
        </fetch-profile>
    </class>
    <class name="Order">
        ...
    </class>
</hibernate-mapping>

Session session = ...;

session.enableFetchProfile( "customer-with-orders" );  // name matches from mapping
Customer customer = (Customer) session.get( Customer.class, customerId );

注意

@FetchProfile definitions are global and it does not matter on which class you place them. You can place the @FetchProfile annotation either onto a class or package (package-info.java). In order to define multiple fetch profiles for the same class or package @FetchProfiles can be used.


<class name="Document">
       <id name="id">
        <generator class="native"/>
    </id>
    <property name="name" not-null="true" length="50"/>
    <property name="summary" not-null="true" length="200" lazy="true"/>
    <property name="text" not-null="true" length="2000" lazy="true"/>
</class>

<target name="instrument" depends="compile">
    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
        <classpath path="${jar.path}"/>
        <classpath path="${classes.dir}"/>
        <classpath refid="lib.class.path"/>
    </taskdef>

    <instrument verbose="true">
        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
            <include name="*.class"/>
        </fileset>
    </instrument>
</target>
Cache Provider class Type Cluster Safe Query Cache Supported
Hashtable (not intended for production use) org.hibernate.cache.HashtableCacheProvider memory   yes
EHCache org.hibernate.cache.EhCacheProvider memory, disk, transactional, clustered yes yes
OSCache org.hibernate.cache.OSCacheProvider memory,disk   yes
SwarmCache org.hibernate.cache.SwarmCacheProvider clustered (ip multicast) yes (clustered invalidation)  
JBoss Cache 1.x org.hibernate.cache.TreeCacheProvider clustered (ip multicast), transactional yes (replication) yes (clock sync req.)
JBoss Cache 2 org.hibernate.cache.jbc.JBossCacheRegionFactory clustered (ip multicast), transactional yes (replication or invalidation) yes (clock sync req.)

  • ENABLE_SELECTIVE (Default and recommended value): entities are not cached unless explicitly marked as cacheable.

  • DISABLE_SELECTIVE: entities are cached unless explicitly marked as not cacheable.

  • ALL: all entities are always cached even if marked as non cacheable.

  • NONE: no entity are cached even if marked as cacheable. This option can make sense to disable second-level cache altogether.

  • read-only

  • read-write

  • nonstrict-read-write

  • transactional

注意

It is recommended to define the cache concurrency strategy per entity rather than using a global one. Use the @org.hibernate.annotations.Cache annotation for that.

@Entity 

@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)

@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
    return tickets;
}

@Cache(
    CacheConcu(1)rrencyStrategy usage();
    String reg(2)ion() default "";
    String inc(3)lude() default "all";
)

1

usage: the given cache concurrency strategy (NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)

2

region (optional): the cache region (default to the fqcn of the class or the fq role name of the collection)

3

include (optional): all to include all properties, non-lazy to only include non lazy properties (default all).


<cache
    usage="tra(1)nsactional|read-write|nonstrict-read-write|read-only"
    region="Re(2)gionName"
    include="a(3)ll|non-lazy"
/>

1

usage(必须)说明了缓存的策略:transactionalread-writenonstrict-read-writeread-only

2

region (可选,默认为类或者集合的名字(class or collection role name)) 指定第二级缓存的区域名(name of the second level cache region)

3

include(可选,默认为 allnon-lazy 当属性级延迟抓取打开时,标记为 lazy="true" 的实体的属性可能无法被缓存


重要

没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。

Cache read-only nonstrict-read-write read-write transactional
Hashtable (not intended for production use) yes yes yes  
EHCache yes yes yes yes
OSCache yes yes yes  
SwarmCache yes yes    
JBoss Cache 1.x yes     yes
JBoss Cache 2 yes     yes

ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set

while ( cats.next() ) {
    Cat cat = (Cat) cats.get(0);
    doSomethingWithACat(cat);
    sess.evict(cat);
}

sessionFactory.evict(Cat.class, catId); //evict a particular Cat

sessionFactory.evict(Cat.class);  //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections

  • CacheMode.NORMAL:从二级缓存中读、写数据。

  • CacheMode.GET:从二级缓存中读取数据,仅在数据更新时对二级缓存写数据。

  • CacheMode.PUT:仅向二级缓存写数据,但不从二级缓存中读数据。

  • CacheMode.REFRESH:仅向二级缓存写数据,但不从二级缓存中读数据。通过 hibernate.cache.use_minimal_puts 的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。

Map cacheEntries = sessionFactory.getStatistics()

        .getSecondLevelCacheStatistics(regionName)
        .getEntries();

hibernate.generate_statistics true
hibernate.cache.use_structured_entries true

hibernate.cache.use_query_cache true
  • org.hibernate.cache.StandardQueryCache,保存缓存的查询结果

  • org.hibernate.cache.UpdateTimestampsCache,保存对可查询表的最近更新的时间戳。它们用于检验查询结果。

重要

If you configure your underlying cache implementation to use expiry or timeouts is very important that the cache timeout of the underlying cache region for the UpdateTimestampsCache be set to a higher value than the timeouts of any of the query caches. In fact, we recommend that the the UpdateTimestampsCache region not be configured for expiry at all. Note, in particular, that an LRU cache expiry policy is never appropriate.

注意

查询缓存不会缓存缓存中实际实体的状态;它只缓存标识符值和值类型的结果。出于这个原因,对于那些作为查询结果缓存的一部分(和集合缓存一样)进行缓存的实体,查询缓存应该和二级缓存一起使用。

List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")

        .setEntity("blogger", blogger)
        .setMaxResults(15)
        .setCacheable(true)
        .setCacheRegion("frontpages")
        .list();
  • 值数据集合

  • 一对多关联(One-to-many Associations)

  • 多对多关联

  • 有序集合类

  • 集合(sets)

  • 包(bags)

Parent p = (Parent) sess.load(Parent.class, id);

Child c = new Child();
c.setParent(p);
p.getChildren().add(c);  //no need to fetch the collection!
sess.flush();
  • 逐一的删除这 18 个数据,再新增三个;

  • 删除整个集合类(只用一句 DELETE 语句),然后逐一添加 5 个数据。

// MBean service registration for a specific SessionFactory

Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); // MBean implementation
stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
server.registerMBean(stats, on); // Register the Mbean on the server
// MBean service registration for all SessionFactory's

Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "all");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); // MBean implementation
server.registerMBean(stats, on); // Register the MBean on the server
  • 在配置期间,将 hibernate.generate_statistics 设置为 truefalse

  • 在运行期间,则可以可以通过 sf.getStatistics().setStatisticsEnabled(true)hibernateStatsBean.setStatisticsEnabled(true)

  • 使用 Session 的普通数据记录,例如打开的 Session 的个数、取得的 JDBC 的连接数等;

  • 实体、集合、查询、缓存等内容的统一数据记录。

  • 和具体实体、集合、查询、缓存相关的详细数据记录

Statistics stats = HibernateUtil.sessionFactory.getStatistics();


double queryCacheHitCount  = stats.getQueryCacheHitCount();
double queryCacheMissCount = stats.getQueryCacheMissCount();
double queryCacheHitRatio =
  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
log.info("Query Hit ratio:" + queryCacheHitRatio);
EntityStatistics entityStats =
  stats.getEntityStatistics( Cat.class.getName() );
long changes =
        entityStats.getInsertCount()
        + entityStats.getUpdateCount()
        + entityStats.getDeleteCount();
log.info(Cat.class.getName() + " changed " + changes + "times"  );