在过去几年里Hibernate不断发展几乎成为Java数据库持久性的事实标准它非常强大灵活而且具备了优异的性能在本文中我们将了解如何使用Java 注释来简化Hibernate代码并使持久层的编码过程变得更为轻松
传统上Hibernate的配置依赖于外部 XML 文件数据库映射被定义为一组 XML 映射文件并且在启动时进行加载创建这些映射有很多方法可以从已有数据库模式或Java类模型中自动创建也可以手工创建无论如何您最终将获得大量的 Hibernate 映射文件此外还可以使用工具通过javadoc样式的注释生成映射文件尽管这样会给您的构建过程增加一个步骤
在最近发布的几个Hibernate版本中出现了一种基于 Java 注释的更为巧妙的新方法借助新的 Hibernate Annotation 库即可一次性地分配所有旧映射文件——一切都会按照您的想法来定义——注释直接嵌入到您的 Java 类中并提供一种强大及灵活的方法来声明持久性映射籍由自动代码完成和语法突出显示功能最近发布的Java IDE也为其提供了有力的支持
Hibernate Annotation还支持新的 EJB 持久性规范这些规范旨在提供一种标准化的 Java 持久性机制由于 Hibernate 还提供了一些扩展因此您可以十分轻松地遵从这些标准并使用 EJB 编程模型来对 Hibernate 持久层进行编码
现在让我们来动手使用Hibernate Annotation
安装 Hibernate Annotation
要使用 Hibernate Annotation您至少需要具备 Hibernate 和Java 可以从 Hibernate 站点 下载 Hibernate 和 Hibernate Annotation库除了标准的 Hibernate JAR 和依赖项之外您还需要 Hibernate Annotations jar 文件(hibernateannotationsjar)Java 持久性 API (lib/ejbpersistencejar)如果您正在使用 Maven只需要向 POM 文件添加相应的依赖项即可如下所示
<dependency> <groupId>orghibernate</groupId> <artifactId>hibernate</artifactId> <version>ga</version> </dependency> <dependency> <groupId>orghibernate</groupId> <artifactId>hibernateannotations</artifactId> <version>ga</version> </dependency> <dependency> <groupId>javaxpersistence</groupId> <artifactId>persistenceapi</artifactId> <version></version> </dependency>
下一步就是获取 Hibernate 会话工厂尽管无需惊天的修改但这一工作与使用 Hibernate Annotations有所不同您需要使用 AnnotationConfiguration 类来建立会话工厂
sessionFactory = new
AnnotationConfiguration()buildSessionFactory();
尽管通常使用 <mapping> 元素来声明持久性类您还是需要在 Hibernate 配置文件(通常是 hibernatecfgxml)中声明持久性类
<!DOCTYPE hibernateconfiguration PUBLIC //Hibernate/Hibernate Configuration DTD //EN configurationdtd> <hibernateconfiguration> <sessionfactory> <mapping class=comonjavamodelplanesdomainPlaneType/> <mapping class=comonjavamodelplanesdomainModelPlane/> </sessionfactory> </hibernateconfiguration>
近期的许多 Java 项目都使用了轻量级的应用框架例如 Spring如果您正在使用 Spring 框架可以使用 AnnotationSessionFactoryBean 类轻松建立一个基于注释的 Hibernate 会话工厂如下所示
<! Hibernate session factory > <bean id=sessionFactory class=orgspringframeworkormhibernateannotationAnnotationSessionFactoryBean> <property name=dataSource> <ref bean=dataSource/> </property> <property name=hibernateProperties> <props> <prop key=hibernatedialect>orghibernatedialectDerbyDialect</prop> <prop key=hibernatehbmddlauto>create</prop> </props> </property> <property name=annotatedClasses> <list> <value>comonjavamodelplanesdomainPlaneType</value> <value>comonjavamodelplanesdomainModelPlane</value> </list> </property> </bean>
第一个持久性类
既然已经知道了如何获得注释所支持的 Hibernate 会话下面让我们来了解一下带注释的持久性类的情况
像在其他任何 Hibernate应用程序中一样带注释的持久性类也是普通 POJO差不多可以说是您需要向 Java 持久性 API (javaxpersistence*)添加依赖项如果您正在使用任何特定于 Hibernate的扩展那很可能就是 Hibernate Annotation 程序包(orghibernateannotations*)但除此之外它们只是具备了持久性注释的普通 POJO 下面是一个简单的例子
@Entitypublic class ModelPlane { private Long id; private String name; @Id public Long getId() { return id; } public void setId(Long id) { thisid = id; } public String getName() { return name; } public void setName(String name) { thisname = name; }}
正像我们所提到的这非常简单@Entity 注释声明该类为持久类@Id 注释可以表明哪种属性是该类中的独特标识符事实上您既可以保持字段(注释成员变量)也可以保持属性(注释getter方法)的持久性后文中将使用基于属性的注释基于注释的持久性的优点之一在于大量使用了默认值(最大的优点就是 惯例优先原则(convention over configuration))例如您无需说明每个属性的持久性——任何属性都被假定为持久的除非您使用 @Transient 注释来说明其他情况这简化了代码相对使用老的 XML 映射文件而言也大幅地减少了输入工作量
生成主键
Hibernate 能够出色地自动生成主键Hibernate/EBJ 注释也可以为主键的自动生成提供丰富的支持允许实现各种策略下面的示例说明了一种常用的方法其中 Hibernate 将会根据底层数据库来确定一种恰当的键生成策略
@Id @GeneratedValue(strategy=GenerationTypeAUTO) public Long getId() { return id; }
定制表和字段映射
默认情况下Hibernate 会将持久类以匹配的名称映射到表和字段中例如前一个类可以与映射到以如下代码创建的表中
CREATE TABLE MODELPLANE ( ID long NAME varchar)
如果您是自己生成并维护数据库那么这种方法很有效通过省略代码可以大大简化代码维护然而这并不能满足所有人的需求有些应用程序需要访问外部数据库而另一些可能需要遵从公司的数据库命名惯例如果有必要您可以使用 @Table 和 @Column 注释来定制您自己的持久性映射如下所示
@Entity@Table(name=T_MODEL_PLANE)public class ModelPlane { private Long id; private String name; @Id @Column(name=PLANE_ID) public Long getId() { return id; } public void setId(Long id) { thisid = id; } @Column(name=PLANE_NAME) public String getName() { return name; } public void setName(String name) { thisname = name; }}
该内容将映射到下表中
CREATE TABLE T_MODEL_PLANE ( PLANE_ID long PLANE_NAME varchar)
也可以使用其他图和列的属性来定制映射这使您可以指定诸如列长度非空约束等详细内容Hibernate支持大量针对这些注释的属性下例中就包含了几种属性
@Column(name=PLANE_ID length= nullable=true) public String getName() { return name; }
映射关系
Java 持久性映射过程中最重要和最复杂的一环就是确定如何映射表间的关系像其他产品一样 Hibernate 在该领域中提供了高度的灵活性但却是以复杂度的增加为代价我们将通过研究几个常见案例来了解如何使用注释来处理这一问题
其中一种最常用的关系就是多对一的关系假定在以上示例中每个 ModelPlane 通过多对一的关系(也就是说每个飞机模型只与一种飞机类型建立联系尽管指定的飞机类型可以与七种飞机模型建立联系)来与 PlaneType 建立联系可如下进行映射
@ManyToOne( cascade = {CascadeTypePERSIST CascadeTypeMERGE} ) public PlaneType getPlaneType() { return planeType; }
CascadeType 值表明 Hibernate 应如何处理级联操作
另一种常用的关系与上述关系相反一对多再对一关系也称为集合在老式的 Hibernate 版本中进行映射或使用注释时集合令人头疼这里我们将简要加以探讨以使您了解如何处理集合例如在以上示例中每个 PlaneType 对象都可能会包含一个 ModelPlanes 集合可映射如下
@OneToMany(mappedBy=planeType cascade=CascadeTypeALL fetch=FetchTypeEAGER) @OrderBy(name) public List<ModelPlane> getModelPlanes() { return modelPlanes; }
命名查询
Hibernate 最优秀的功能之一就在于它能够在您的映射文件中声明命名查询随后即可通过代码中的名称调用此类查询这使您可以专注于查询而避免了 SQL 或者 HQL 代码分散于整个应用程序中的情况
也可以使用注释来实现命名查询可以使用 @NamedQueries 和 @NamedQuery 注释如下所示
@NamedQueries( { @NamedQuery( name=planeTypefindById query=select p from PlaneType p left join fetch pmodelPlanes where id=:id ) @NamedQuery( name=planeTypefindAll query=select p from PlaneType p ) @NamedQuery( name=planeTypedelete query=delete from PlaneType where id=:id ) })
一旦完成了定义您就可以像调用其他任何其他命名查询一样来调用它们
结束语
Hibernate 注释提供了强大而精致的 API简化了 Java 数据库中的持久性代码本文中只进行了简单的讨论您可以选择遵从标准并使用 Java 持久性 API也可以利用特定于 Hibernate的扩展这些功能以损失可移植性为代价提供了更为强大的功能和更高的灵活性无论如何通过消除对 XML 映射文件的需求Hibernate 注释将简化应用程序的维护同时也可以使您对EJB 有初步认识来试试吧!
资源
Hibernate 站点
Spring 站点
作者简介 John Ferguson Smart 从年起涉足IT行业从年起开始参与JEE开发