一个非常高层次的Hibernate体系结构图:
这幅图展示了Hibernate使用数据库和配置文件数据来为应用程序提供持久化服务(和持久化的对象)。
我们展示一个更详细的运行时结构图。不幸的是,Hibernate很灵活并且支持并且支持多种运行方式。我们展示一下两种极端情况。轻型体系中,应用程序自己提供JDBC连接,并且自行管理事务。这种方式使用了Hibernate API的一个最小子集。
全面解决体系中,对于应用程序来说,所有的底层JDBC/JTA API都被抽象了,Hibernate会替你照管所有的细节。
下面是图中一些对象的定义:
-
SessionFactory (org.hibernate.SessionFactory)
-
是对单一数据库的已编译映射文件的线程安全的不可变的高速缓存。它是Session的工厂,是ConnectionProvider的客户。可能持有一个可选的可在进程级别或集群级别事务间重用的(二级)数据缓存。
会话 Session (org.hibernate.Session)
-
单线程的短生命周期的对象,是应用程序和持久化存储的一次对话。封装了一个JDBC连接,也是Transaction的工厂。保持一个持久化对象的强制(第一级)缓存,用来遍历对象图或者根据标识符查询对象。
持久化对象和集合 ( Persistent objects and collections)
-
包含持久化状态和商业功能的短生命周期的单线程对象。它们可能是普通的JavaBean或POJO,唯一特别的是它们通常跟且只跟一个Session相关联。一旦Session被关闭,它们将游离并能在任何应用层被使用(例如,直接作为表示层的数据传输对象)。
临时分离对象和集合(Transient and detached objects and collections)
-
当前没有跟Session关联的持久化类的实例。它们可能是应用程序实例化但是还没有持久化的或者是被已关闭的Session实例化的。
事务 Transaction (org.hibernate.Transaction)
-
(可选)单线程,短生命周期的对象,应用程序用它来表示一批工作的原子操作。是底层JDBC,JTA或者CORBA事务的抽象。一个Session某些情况下可能跨越多个Transaction 事务。然而,使用底层API或者Transaction进行的事务划分不是可选的。
ConnectionProvider (org.hibernate.connection.ConnectionProvider)
-
(可选) JDBC连接的工厂和连接池。底层 Datasource或DriverManager的抽象应用。对应用程序不可见,但可以被开发者扩展/实现。
TransactionFactory (org.hibernate.TransactionFactory)
-
(可选)事务实例的工厂。对应用程序不可见,但可以被开发者扩展/实现。
扩展接口(Extension Interfaces)
-
Hibernate 提供很多可选的可扩展接口,你可以实现它们来定制你的客持久化层的行为。在API中查看更多细节。
在上面的轻型结构中,程序没有使用Transaction / TransactionFactory 或者ConnectionProvider API,直接和JTA/JDBC对话了。
一个持久化类的实例可以使根据持久化上下文(persistence context)定义的三种不同状态之一。Hibernate的Session对象就是持久化上下文(persistence context):
-
临时状态(transient)
-
这样的实例没有从来没有跟任何的持久化上下文相关联。它没有持久化的标识(主键值)。
持久化状态(persistent)
-
实例现在正跟一个持久化上下文相关联。它有持久化的标识(主键值),可能对应跟数据库中的某一行。在一个特定的持久化上下文中,Hibernate 保证 持久化标识和Java标识是等价的(在对象的内存中)。
游离状态(detached)
-
曾经跟持久化上下文关联但是上下文已经关闭或者在另一个进程中连续使用的实例。它有持久化标识并且可能对应数据库中的某一行。对于游离态的实例,Hibernate并不保证持久化标识和Java标识的关系。
JMX是管理Java组件的J2EE标准。Hibernate可以被标准的JMX服务管理。我们在发行包中提供一个MBean的实现:org.hibernate.jmx.HibernateService。
JBoss用户指南提供了怎样在JBoss应用服务器中将Hibernate作为JMX服务发布的例子。在JBoss应用服务器中,如果使用JMX还可以得到这些好处:
-
会话管理(Session Management): Hibernate会话的生命周期能够自动被绑定到JTA事务中。这意味着不再需要手动地打开和关闭会话,这将成为JBoss EJB 拦截器的工作。你再也不必担心代码中事务的划分(除非你愿意用可选的Hibernate事务API写一个便捷的持久化层)。调用HibernateContext访问一个会话。
-
HAR deployment: 通常你使用JBoss服务部署描述符(在EAR或SAR文件中)部署Hibernate JMX服务,它支持Hibernate SessionFactory的所有常用配置操作。然而,你还是要在部署描述符中命名你所有的映射文件。
参考JBoss 应用服务器用户指南获得更多信息。
另一个JMX服务的有用的特征是Hibernate统计,参看 3.4.6节, “Hibernate 统计”。
很多使用Hiberante的应用程序需要一些“上下文”形式的会话,这样的会话的作用贯穿在整个上下文范围中。然而,在整个应用中定义上下文的条件通常是不同的;并且不同的上下文对当前概念也有不同的定义范围。使用Hibernate3.0以前的版本的应用程序要么利用自产的基于当前线程的上下文会话(像HibernateUtil一样的辅助类),要么利用提供代理/基于侦听的上下文会话的第三方框架(例如Spring或Pico)。
从 3.0.1开始,Hibernate增加了 SessionFactory.getCurrentSession()方法。 最初这种设想是JTA事务的用法,JTA事务定义了范围和当前会话的上下文。Hibernate团队获得了大量成熟的单机JTA事务管理器的实现,他们主张大部分应用程序应该使用JTA事务管理器不管是不是在J2EE容器中部署。基于此,基于JTA的上下文会话是你曾经需要用到的。
然而在 3.1中,SessionFactory.getCurrentSession()的后台处理现在可以插拔。为此,增加了一个新的扩展接口(org.hibernate.context.CurrentSessionContext) 和新的配置参数 (hibernate.current_session_context_class)来允许定义当前会话的范围和上下文的热插拔。
在Java文档中查看 org.hibernate.context.CurrentSessionContext 接口更详细的讨论。它定义了一个唯一的方法currentSession(),通过它接口的实现对跟踪当前上下文会话变得可靠。在下表里,Hibernate提供了接口的三个实现。
-
org.hibernate.context.JTASessionContext - 当前会话被JTA事务跟踪并检查。处理方法跟旧的JTA完全相同,也是唯一做法。在Java文档中查看详细信息。
-
org.hibernate.context.ThreadLocalSessionContext - 当前会话被执行的线程跟踪,在Java文档中查看详细信息。
-
org.hibernate.context.ManagedSessionContext - 当前会话被执行的线程跟踪,但是你应该在这个类中使用静态方法绑定和解除一个会话实例,它不会打开,刷新或关闭一个会话。
前两个实现提供了一种“一个会话一个数据库事务”的编程模式,也被称为是会话每请求(session-per-request)。一个Hibernate会话的开始和结束在数据库事务期间被定义。如果你在没有JTA的简单的JSE中使用可编程的数据库划分,建议你使用Hibernate事务API在你的代码中隐藏底层事务系统。如果你使用JTA,使用JTA接口划分事务。如果你在一个支持CMT的EJB容器中执行,事务界限会被明确定义,你不需要在代码中作任何事物或会话的划分。参考 第11章,事物和并发 获得更多信息和代码示例。
hibernate.current_session_context_class 配置参数定义了应该使用哪一个org.hibernate.context.CurrentSessionContext的实现 。注意,为了向后兼容,如果没有设置配置参数,而是配置了org.hibernate.transaction.TransactionManagerLookup ,Hibernate会使用org.hibernate.context.JTASessionContext。通常,这个参数只是命名要使用的实现类;上面的三个实现分别有简称“jta”,“thread”,和“managed”。