`
laodaobazi
  • 浏览: 272786 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Hibernate对JPA的扩展

阅读更多

Hibernate 3.1 提供了多种附加的注解,这些注解可以与EJB3的实体混合/匹配使用。
他们被设计成EJB3注解的自然扩展。

 

为了强化EJB3的能力,Hibernate提供了与其自身特性相吻合的特殊注解。
org.hibernate.annotations 包已包含了所有的这些注解扩展。

 

实体:Entity

@org.hibernate.annotations.Entity
追加了可能需要的额外的元数据,
而这些元数据超出了标准@Entity 中所定义的元数据。

mutable: 此实体是否为可变的

dynamicInsert: 用动态SQL新增

dynamicUpdate: 用动态SQL更新

selectBeforeUpdate: 指明Hibernate从不运行SQL UPDATE除非能确定对象的确已被修改

polymorphism: (指出)实体多态是PolymorphismType.IMPLICIT(默认)还是PolymorphismType.EXPLICIT

persister: allow the overriding of the default persister implementation

允许对默认持久实现(persister implementation)的覆盖

optimisticLock: 乐观锁策略(OptimisticLockType.VERSION, OptimisticLockType.NONE, OptimisticLockType.DIRTY 或 OptimisticLockType.ALL)

 

提示:

@javax.persistence.Entity仍是必选的(mandatory),
@org.hibernate.annotations.Entity不是取代品。

 

以下是一些附加的Hibernate注解扩展:

 

@org.hibernate.annotations.BatchSize 允许你定义批量抓取该实体的实例数量(如:@BatchSize(size=4) )。
当加载一特定的实体时,Hibernate将加载在持久上下文中未经初始化的同类型实体,直至批量数量(上限)。

 

@org.hibernate.annotations.Proxy
定义了实体的延迟属性。Lazy(默认为true)定义了类是否为延迟(加载)。
proxyClassName是用来生成代理的接口(默认为该类本身)。

 

@org.hibernate.annotations.Where 定义了当获取类实例时所用的SQL WHERE子句(该SQL WHERE子句为可选)。

 

@org.hibernate.annotations.Check
定义了在DDL语句中定义的合法性检查约束(该约束为可选)。

 

@OnDelete(action=OnDeleteAction.CASCADE)
定义于被连接(joined)的子类:在删除时使用SQL级连删除,而非通常的Hibernate删除机制。

 

@Table(name="tableName", indexes = {
@Index(name="index1", columnNames={"column1", "column2"} ) } )
在tableName表的字段上创建定义好的索引。该注解可以被应用于关键表或者是其他次要的表。
@Tables 注解允许你在不同的表上应用索引。
此注解预期在使用
@javax.persistence.Table
@javax.persistence.SecondaryTable 的地方中出现.
@org.hibernate.annotations.Table 是对
@javax.persistence.Table 的补充而不是它的替代品。

 

@Entity
@BatchSize(size=5)
@org.hibernate.annotations.Entity(
selectBeforeUpdate = true,
dynamicInsert = true, dynamicUpdate = true,
optimisticLock = OptimisticLockType.ALL,
polymorphism = PolymorphismType.EXPLICIT)
@Where(clause="1=1")
@org.hibernate.annotations.Table(name="Forest", indexes = { @Index(name="idx", columnNames = { "name", "length" } ) } )
public class Forest { ... }

 

@Entity
@Inheritance(
strategy=InheritanceType.JOINED
)
public class Vegetable { ... }

@Entity
@OnDelete(action=OnDeleteAction.CASCADE)
public class Carrot extends Vegetable { ... }

 

主键:Identifier

@org.hibernate.annotations.GenericGenerator
允许你定义一个Hibernate特定的id生成器。

 

@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
public String getId() {

@Id @GeneratedValue(generator="hibseq")
@GenericGenerator(name="hibseq", strategy = "seqhilo",
parameters = {
@Parameter(name="max_lo", value = "5"),
@Parameter(name="sequence", value="heybabyhey")
}
)
public Integer getId() {

 

strategy 可以是Hibernate3生成器策略的简称,或者是一个IdentifierGenerator 实现的(带包路径的)全限定类名。
你可以通过parameters 属性增加一些参数。

 

Property

Access type

访问类型是根据@Id@EmbeddedId 在实体继承层次中所处的位置推演而得的。

子实体(Sub-entities),内嵌对象和被映射的父类均从根实体(root entity)继承访问类型。

 

在Hibernate中,你可以把访问类型覆盖成:

 

使用定制的访问类型策略

 

为支持这种行为,Hibernate引入了@AccessType注解。你可以对以下元素定义访问类型:

 

实体

父类

可内嵌的对象

属性

 

被注解元素的访问类型会被覆盖,若覆盖是在类级别上,则所有的属性继承访问类型。
对于根实体,其访问类型会被认为是整个继承层次中的缺省设置(可在类或属性一级覆盖

 

若访问类型被标以"property",则Hibernate会扫描getter方法的注解,若访问类型被标以"field",

则扫描字段的注解。否则,扫描标为@Id或@embeddedId的元素。

 

你可以覆盖某个属性(property)的访问类型,但是受注解的元素将不受影响:例如一个具有field访问类型的实体,(我们)可以将某个字段标注为 @AccessType("property"),则该字段的访问类型随之将成为property,但是其他字段上依然需要携带注解。

 

若父类或可内嵌的对象没有被注解,则使用根实体的访问类型(即使已经在非直系父类或可内嵌对象上定义了访问类型)。此时俄罗斯套娃(Russian doll)原理就不再适用。(译注:俄罗斯套娃(матрёшка或 матрешка)是俄罗斯特产木制玩具,一般由多个一样图案的空心木娃娃一个套一个组成,最多可达十多个,通常为圆柱形,底部平坦可以直立。)

 

@Entity
public class Person implements Serializable {
@Id @GeneratedValue //access type field
Integer id;

@Embedded
@AttributeOverrides({
@AttributeOverride(name = "iso2", column = @Column(name = "bornIso2")),
@AttributeOverride(name = "name", column = @Column(name = "bornCountryName"))
})
Country bornIn;
}

@Embeddable
@AccessType("property") //override access type for all properties in Country
public class Country implements Serializable {
private String iso2;
private String name;

public String getIso2() {
return iso2;
}

public void setIso2(String iso2) {
this.iso2 = iso2;
}

@Column(name = "countryName")
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

 

Formula

有时候,你想让数据库,而非JVM,来替你完成一些计算,也可能想创建某种虚拟字段(译注:即数据库视图)。你可以使用一段SQL(亦称为公式),而不是将属性映射到(物理)字段。 这种属性是只读的(属性值由公求得)。

 

@Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()

 SQL片段可以是任意复杂的,甚至可包含子查询。

 

Type

@org.hibernate.annotations.Type
覆盖了Hibernate所用的默认类型:这通常不是必须的,因为类型可以由Hibernate正确推得。
关于Hibernate类型的详细信息,请参考Hibernate使用手册。

 

@org.hibernate.annotations.TypeDef
@org.hibernate.annotations.TypeDefs 允许你来声明类型定义。
这些注解被置于类或包一级。注意,对session factory来说,
这些定义将是全局的(即使定义于类一级),并且类型定义必须先于任何使用。

 

@TypeDefs(
{
@TypeDef(
name="caster",
typeClass = CasterStringType.class,
parameters = {
@Parameter(name="cast", value="lower")
}
)
}
)
package org.hibernate.test.annotations.entity;

...
public class Forest {
@Type(type="caster")
public String getSmallText() {
...
}

 当使用组合的用户自定义类型时,你必须自己来表达字段定义。
@Columns 就是为了此目的而引入的。

 

@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
@Columns(columns = {
@Column(name="r_amount"),
@Column(name="r_currency")
})
public MonetaryAmount getAmount() {
return amount;
}

public class MonetaryAmount implements Serializable {
private BigDecimal amount;
private Currency currency;
...
}

 

Index

通过在字段属性(property)上使用@Index 注解,
可以在特定字段上定义索引,columnNames属性(attribute)将随之被忽略。

 

@Column(secondaryTable="Cat1")
@Index(name="story1index")
public String getStoryPart1() {
return storyPart1;
}

 

Inheritance

SINGLE_TABLE 是个功能强大的策略,但有时,特别对遗留系统而言,
是无法加入一个额外的识别符字段(discriminator column)。
由此,Hibernate引入了识别符公式(discriminator formula)的概念:
@DiscriminatorFormula@DiscriminatorColumn 的替代品,
它使用SQL片段作为识别符解决方案的公式( 不需要有一个专门的字段)。

@Entity
@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")
public class Forest { ... }

 

Association related annotations

默认情况下,当预期的被关联元素不在数据库中(关乎关联字段的id错误),致使Hiberante无法解决关联性问题时,Hibernate就会抛出异常。
这对遗留schema和历经拙劣维护的schema而言,这或有许多不便。
此时,你可用 @NotFound 注解让Hibernate略过这样的元素而不是抛出异常。
该注解可用于 @OneToOne (有外键)、 @ManyToOne
@OneToMany @ManyToMany 关联。

@Entity
public class Child {
...
@ManyToOne
@NotFound(action=NotFoundAction.IGNORE)
public Parent getParent() { ... }
...
}

 

Collection related annotations

Parameter annotations

以下是可能的设置方式

 

用@BatchSizebatch设置集合的batch大小

用@Where注解设置Where子句

用注解@Check来设置check子句

用注解@OrderBy来设置SQL的order by子句

利用@OnDelete(action=OnDeleteAction.CASCADE) 注解设置级连删除策略

 

你也可以利用@Sort 注解定义一个排序比较器(sort comparator),表明希望的比较器类型,无序、自然顺序或自定义排序,三者择一。若你想用你自己实现的comparator,
你还需要利用comparator 属性(attribute)指明实现类。

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
@Where(clause="1=1")
@OnDelete(action=OnDeleteAction.CASCADE)
public SortedSet<Ticket> getTickets() {
return tickets;
}

 关于这些注解更详细的信息,请参阅此前的描述。

 

Extra collection types

比EJB3更胜一筹的是,Hibernate Annotations支持真正的ListArray
映射集合的方式和以前完全一样,只不过要新增@IndexColumn 注解。该注解允许你指明存放索引值的字段。你还可以定义代表数据库中首个元素的索引值(亦称为索引基数)。常见取值为01

 

@OneToMany(cascade = CascadeType.ALL)
@IndexColumn(name = "drawer_position", base=1)
public List<Drawer> getDrawers() {
return drawers;
}

 假如你忘了设置@IndexColumn ,Hibernate会采用bag语义(译注:即允许重复元素的无序集合)。

 

Hibernate Annotations还支持核心类型集合(Integer, String, Enums, ......)、
可内嵌对象的集合,甚至基本类型数组。这就是所谓的元素集合。

 

元素集合可用@CollectionOfElements来注解(作为@OneToMany的替代)。
为了定义集合表(译注:即存放集合元素的表,与下面提到的主表对应),要在关联属性上使用@JoinTable注解,joinColumns定义了介乎实体主表与集合表之间的连接字段(inverseJoincolumn是无效的且其值应为空)。
对于核心类型的集合或基本类型数组,你可以在关联属性上用@Column 来覆盖存放元素值的字段的定义。你还可以用@AttributeOverride来覆盖存放可内嵌对象的字段的定义。

@Entity
public class Boy {
private Integer id;
private Set<String> nickNames = new HashSet<String>();
private int[] favoriteNumbers;
private Set<Toy> favoriteToys = new HashSet<Toy>();
private Set<Character> characters = new HashSet<Character>();

@Id @GeneratedValue
public Integer getId() {
return id;
}

@CollectionOfElements
public Set<String> getNickNames() {
return nickNames;
}

@CollectionOfElements
@JoinTable(
table=@Table(name="BoyFavoriteNumbers"),
joinColumns = @JoinColumn(name="BoyId")
)
@Column(name="favoriteNumber", nullable=false)
@IndexColumn(name="nbr_index")
public int[] getFavoriteNumbers() {
return favoriteNumbers;
}

@CollectionOfElements
@AttributeOverride( name="serial", column=@Column(name="serial_nbr") )
public Set<Toy> getFavoriteToys() {
return favoriteToys;
}

@CollectionOfElements
public Set<Character> getCharacters() {
return characters;
}
...
}

public enum Character {
GENTLE,
NORMAL,
AGGRESSIVE,
ATTENTIVE,
VIOLENT,
CRAFTY
}

@Embeddable
public class Toy {
public String name;
public String serial;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSerial() {
return serial;
}

public void setSerial(String serial) {
this.serial = serial;
}

public boolean equals(Object o) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;

final Toy toy = (Toy) o;

if ( !name.equals( toy.name ) ) return false;
if ( !serial.equals( toy.serial ) ) return false;

return true;
}

public int hashCode() {
int result;
result = name.hashCode();
result = 29 * result + serial.hashCode();
return result;
}
}
 

旧版的Hibernate Annotations用@OneToMany 来标识集合元素。
由于语义矛盾,我们引入了@CollectionOfElements 注解。
@OneToMany 来标识集合元素的这种旧有方式目前尚有效,但是不推荐使用,而且在以后的发布版本中不再支持这种方式。

 

Cache

为了优化数据库访问,你可以激活所谓的Hibernate二级缓存。该缓存是可以按每个实体和集合进行配置的。

 

@org.hibernate.annotations.Cache 定义了缓存策略及给定的二级缓存的范围。此注解适用于根实体(非子实体),还有集合。

 

@Entity
@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(
CacheConcurrencyStrategy usage();
String region() default "";
String include() default "all";
)

 

usage: 给定缓存的并发策略(NONE,
READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)

region (可选的):缓存范围(默认为类的全限定类名或是集合的全限定角色名)

include (可选的):值为all时包括了所有的属性(proterty),
为non-lazy时仅含非延迟属性(默认值为all)

 

Filters

Hibernate具有数据过滤器的概念,可在运行期应用于一个给定的session。过滤器需要事先定义好。

 

@org.hibernate.annotations.FilterDef
@FilterDefs 定义过滤器声明,为同名过滤器所用。
过滤器声明带有一个name()和一个parameters()数组,@ParamDef包含name和type,你还可以为给定的@filterDef定义一个defaultCondition()参数,当@Filter中没有任何定义时,可使用该参数定义缺省条件。
@FilterDef
(s)可以在类或包一级进行定义。

 

现在我们来定义应用于实体或集合加载时的SQL过滤器子句。我们使用@Filter ,并将其置于实体或集合元素上。

@Entity
@FilterDef(name="minLength", parameters={ @ParamDef( name="minLength", type="integer" ) } )
@Filters( {
@Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
@Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }
 

Queries

由于Hibernate引入了
@org.hibernate.annotations.NamedQuery ,
@org.hibernate.annotations.NamedQueries ,
@org.hibernate.annotations.NamedNativeQuery
@org.hibernate.annotations.NamedNativeQueries 命名式查询,因此Hibernate在命名式查询上比EBJ3规范中所定义的命名式查询提供了更多的特性。
他们在标准版中添加了可作为替代品的一些属性(attributes):

 

flushMode: 定义查询的刷新模式(Always, Auto, Commit或Never)

cacheable: 查询该不该被缓存

cacheRegion: 若查询已被缓存时所用缓存的范围

fetchSize: 针对该查询的JDBC statement单次获取记录的数目

timeout: 查询超时

callable: 仅用于本地化查询(native query),对于存储过程设为true

comment: 一旦激活注释功能,我们会在向数据库交送查询请求时看到注释

cacheMode: 缓存交护模式(get, ignore,normal,或refresh)

readOnly: 不管是否从查询获取元素都是在只读模式下

 

注意,EJB3已公开的最终草案中引入了@QueryHint 的概念,
这可能是定义hints更好的方法。

 

Comments

 

1。与EJB3的实体混合/匹配使用

2。为了强化EJB3的能力

4。(指出)实体多态是PolymorphismType.IMPLICIT(默认)还是PolymorphismType.EXPLICIT

5。允许对默认持久实现(persister implementation)的覆盖

6。@javax.persistence.Entity依然是必须遵循的,@org.hibernate.annotations.Entity无意于取而代之。

7。@org.hibernate.annotations.BatchSize</literal>允许你定义批量抓取该实体的实例数量

8。......Hibernate将加载在持久上下文中未经初始化的同类型实体,直至批量数量(上限)

9。@org.hibernate.annotations.Proxy</literal>定义了实体的延迟属性。lazy(默认为true)定义类是否延迟(加载)。......(默认为该类本身)

10。@OnDelete(action=OnDeleteAction.CASCADE)</literal>定义于被连接(joined)的子类:......而非通常的......

11。在tableName表的字段上创建定义好的索引。该注解可以被应用于关键表或者是其他次要的表。

12。<literal>strategy</literal>可以是Hibernate3生成器策略的简称,或者是一 个<classname>IdentifierGenerator</classname>实现的(带包路径的)全限定类名。

13。访问类型是根据<literal>@Id</literal> 或<literal>@EmbeddedId</literal>在实体继承层次中所处的位置推演而得的。子实体(Sub- entities),内嵌对象和被映射的父类均从根实体(root entity)继承访问类型。

14。你可以覆盖访问类型为:

15。在类层次或属性层次对访问类型进行微调

16。可内嵌的对象

17。被注解元素的访问类型会被覆盖......对于根实体,其访问类型会被认为是整个继承层次中的缺省设置(可在类或属性一级覆盖)

18。若访问类型被标以"property",则Hibernate会扫描getter方法的注解,若访问类型被标以"field",则扫描字段处的注解。

19。你可以覆盖某个属性(property)的访问类型,但是受注解的元素将不受影响:例如一个具 有<literal>field</literal>访问类型的实体,(我们)可以将某个字段标注 为<literal>@AccessType("property")</literal>,则该字段的访问类型随之将成为 property,但是其他字段上依然需要携带注解(此处原文就有误,冒出了两个the)

20。若父类或可内嵌对象没有被注解,则使用根实体的访问类型(即使已经在非直系父类或可内嵌对象上定义了访问类型)。

22。这通常不是必须的,因为类型可以由Hibernate正确推得

23。这些注解被置于类或包一级。......(即使定义于类一级),并且类型定义必须先于任何使用。

24。......,可以在特定字段上定义索引,columnNames属性(attribute)将随之被忽略。

25。SINGLE_TABLE是一种很不错的策略,......

26。鉴别字段?鉴别器?还是识别符?(个人觉得识别符不错,不过之前的H3 Reference中文版好像用的是鉴别器)

27。......,针对识别符方案,使用一段SQL语句作为公式(无需专用字段)--与26有同样问题

29。对遗留schema和历经拙劣维护的schema而言,这或许多有不便......该注解可用于......关联。

30。用@BatchSize为集合设置批量大小?,用@Where设置where子句,用@Check设置check子句,用@OrderBy设置 SQL的order by子句,利用@OnDelete(action=OnDeleteAction.CASCADE)设置级联删除策略

31。你也可以利用<literal>@Sort</literal>注解定义一个排序比较器(sort comparator),表明希望的比较器类型,无序,自然顺序或自定义排序,三者择一。

32。你还需要利用<literal>comparator</literal>属性(attribute)指明实现类。

33。比EJB3更胜一筹的是,Hibernate Annotations支持真正的<classname>List</classname>和<classname>Array</classname>

34。以与往常一样的方式映射集合,同时增加@<literal>IndexColumn</literal>。该注解允许你指明存放索引值的字段。你还可以定义代表数据库中首个元素的索引值(亦称为索引基数)。常见取值为0或1。

35。假如你忘了设置<literal>@IndexColumn</literal>,Hibernate会采用bag语义(译注:即允许重复元素的无序集合)

36。Hibernate Annotations还支持核心类型集合(......),可内嵌对象集合,甚至基本类型数组。

37。元素集合......(作为<literal>@OneToMany</literal>的替代)

38。为了定义集合表(译注:即存放集合元素的表,与下面提到的主表对应),要在关联属性上使用@JoinTable注解,joinColumns定义了介乎实体主表与集合表之间的连接字段

39。对于核心类型的集合或基本类型数组,你可以在关联属性上用<literal>@Column</literal>来覆盖存 放元素值的字段的定义。你还可以用<literal>@AttributeOverride</literal>来覆盖存放可内 嵌对象的字段的定义。

40。旧版本的Hibernate Annotations......由于语义矛盾,......

41。但被认为是不推荐使用的

42。为了优化数据库访问,你可以激活所谓的Hibernate二级缓存。该缓存是可以按每个实体和集合进行配置的。

43。......以及给定二级缓存的范围。......根实体(不是子实体),还有集合

44。给定缓存的并发策略......默认为类的全限定类名或是集合的全限定角色名

45。Hibernate具有数据过滤器的概念,可在运行期应用于一个给定的session。过滤器需要事先定义好。

46。......或......定义过滤器声明,为同名过滤器所用。

47。过滤器声明带有一个name()和一个parameters()序 列,<literal>@ParamDef</literal>包含name和type,你还可以为给定 的<literal>@filterDef</literal>定义一个defaultCondition()参数,以设置 当<literal>@Filter</literal>中没有任何定义时所使用的缺省条 件。<literal>@FilterDef</literal>(s)可以在类或包一级进行定义。

48。现在我们来定义应用于实体或集合加载时的SQL过滤器子句。我们使用<literal>@Filter</literal>,并将其置于实体或集合元素上

49。Hibernate引入了......和......,较之EJB3规范中所定义的具名查询,具备了更多的特性。它们新增了一些属性,可以作为标准版的替代方案。

50。flushMode: 定义查询的刷新模式(Always, Auto, Commit或Never)

51。fetchSize: 针对该查询的JDBC statement单次获取记录的数目

52。callable: 仅用于本地化查询(native queries), ......

53。commont:一旦激活注释功能,我们会在向数据库交送查询请求时看到注释

54。readOnly:不论元素是否获取自数据库查询,均处于只读模式

55。这可能是定义hints更好的方法(此处的query hints应该是专用术语)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics