HIbernate注解
Hibernate注解
文章分类:Web前端
@org.hibernate.annotations.Entity(dynamicUpdate=true,dynamicInsert=true)
类定义前添加;
作用:当只需更新某个表的部分字段时,其他字段不会更新。在性能优化方面有一定的帮助。
基本属性映射
通过 @Basic 可以声明属性的存取策略:
@Basic(fetch=FetchType.EAGER) 即时获取(默认的存取策略)
@Basic(fetch=FetchType.LAZY) 延迟获取
通过 @Temporal 定义映射到数据库的时间精度:
@Temporal(TemporalType=DATE) 日期
@Temporal(TemporalType=TIME) 时间
@Temporal(TemporalType=TIMESTAMP) 两者兼具
使用 @Lob 映射Blob或Clob类型:根据属性类型决定
java.sql.CLOB, Character[], char[], String 将映射为 Clob
java.sql.BLOB, Byte[], byte[], serializable 将映射为 Blob
利用Hibernate Annotations进行对象关联映射(一)
1. 简介
在使用Hibernate的时候,对于对象之间的关联,往往是比较复杂的,比如如何映射多对多关系,如何映射双向/单向的关系等等。
在JDK5.0出来之前,往往很头疼于映射一个Collection类型的属性,好像有n多的参数需要设置,inverse、mappedby等等又是什么意思呢?如何确定关联双方的维护关系?
当JDK5.0横空出世之后,它带来的Generic、Annotation等等新的特性,给Hibernate带来了巨大的活力。随着新版本Hibernate的发布,我们可以发现,使用Hibernate,使用JDK的新特性,给我们的开发工作带来了很大的便利。
现在,我可以自由地创建领域模型类图,而很少关心它的存储,因为,我只需要用很少的几个Annotation,一切似乎都在完美地运转,使用它的缺省设置,无需过多的定义,就能满足我的项目中绝大部分的要求。
是不是很吸引人?下面,我尝试将一对一、一对多、多对多、双向、单向等概念,一次性集中对照着讨论一下,然后以一些例子来进行具体的说明,希望那些和我一样,对hibernate有兴趣的、曾经头疼于它的那些Collection等映射方法的朋友们有些帮助。
下面这一章的内容有点晦涩,如果你看不下去了,可以看看后面举例的那一章,映射设置与SQL语句对照着看,可能更加容易理解。(女性朋友们不要骂我,我不是SuperMan J )
2. 关联类型及映射方法
2.1 一对一
两个实体之间是一对一的关系。我们可以想象一下,一对一关系,表明两个实体之间关系非常密切。两个实体,在数据库中会映射成两张表。所以这两张表之间必定需要建立关联。有两种方法可以实现一对一的关系映射。
1、 两张表使用同样的主键值:
@Entitypublic class Body { @Id public Long getId() { return id; } @OneToOne(cascade = CascadeType.ALL, usePKasFK=true) public Heart getHeart() { return heart; } ...}@Entitypublic class Heart { @Id(generate = GeneratorType.NONE) public Long getId() { ...}}以上例子表明两张表将使用同样的键值。但是这种方法在hibernate3beta2版本中仍然是有局限的。
2、 通过外键关联
也就是在拥有者一边,指定它的外键
@Entitypublic class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="passport_fk") public Passport getPassport() { ... }@Entitypublic class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ...} 上边的例子就是一个使用外键的实例。使用JoinColumn声明来指定数据库中的外键。上边的例子同时也表明,这是一个双向的一对一关系。在这种双向的关系中,你必须让拥有者这一边,负责被拥有者的创建、删除、更新操作(cascade = CascadeType.ALL)。同时,你必须在被拥有者那边定义,说它的信息不需要自己维护,这是通过定义mappedBy属性来决定的。这个属性的值,就是它的拥有者对被拥有者关联的属性的值。如上边的例子,mappedBy的意思就是说:我的(Passport的)信息是由对方的(Customer的)passport属性来映射的。
2.1.1 更多的解释
1、 如果没有标识cascade属性的值,表明它们之间没有任何关联操作。你必须先将属性的值保存之后,才能将主体的值保存。
2、 双向一对一关联中,可以在任何一方设置mappedBy属性,也可以在任何一方都不设置mappedBy。如果没有任何一方设置mappedBy,就意味着在双方的数据库表中都会保留着对对方的关联外键(双向关联)。在双向一对一关联中,完全没有必要在双方的数据库表中都保留对对方的关联外键,形成数据库主键双向关联。所以最好能设置一下mappedBy属性。虽然数据库中没有双方关联,但是在实体层,你仍然可以从任意一方访问到另外一方。
3、 如果有一方设置了mappedBy属性,则在设置mappedBy一方,不会有对方的外键关联。
2.2 多对一
多对一的关系比较简单,一个实体到另外一个实体的应用,在数据库中就表现为多对一的关系。
@Entity()public class Flight implements Serializable { @ManyToOne( cascade = {CascadeType.CREATE, CascadeType.MERGE} ) @JoinColumn(name="COMP_ID") public Company getCompany() { return company; } ...}上述例子表明,这是一种多对一关系,外键是COMP_ID。这个外键的定义也是可选的,在生成数据库的时候,如果你没有定义这个外键的名称,那么默认的规则就是“属性名_属性对应的ID”,如上例,假设Company的主键名为ID,那么,如果你不指定JoinColumn,默认生成的外键名就是“company_id”,因为company是属性的名称,而id是Company的主键名称。
2.2.1 更多的解释
多对一,如果是双向的,就意味着另外一端是一对多,这种一对多的关系,在数据库里面建立外键的时候,必定是在多的那一端,创建一个外键,关联到一那一端。所以ManyToOne是没有mappedBy属性的。只有在双向一对多关联中,才能在多的那端定义mappedBy属性。
2.3 一对多
通常,一对多的关系,在实体里面的表现就是一个集合对象。由于JDK5可以使用范型,所以,除非你使用了范型,否则,必须在一对多的关系中指定目标实体的名称。
2.3.1 双向一对多
@Entitypublic class Troop { @OneToMany(mappedBy="troop") public Set<Soldier> getSoldiers() { ...}@Entitypublic class Soldier { @ManyToOne @JoinColumn(name="troop_fk") public Troop getTroop() { ...}上面就是一个双向的例子。在mappedBy这一端,你不能定义任何物理参数(即有关数据库主键、外键之类的定义)。其实,所谓mappedBy,意思就是在mappedBy这一端,数据库里面没有任何外键关联到对方的表。这种关联是在对方的表中建立的。
2.3.2 单向一对多
所谓单向一对多,也就是说在“一”这一端,能访问所有的“多”,但是在“多”这一端却不能访问“一”的信息。
实现这种单向一对多,也有两种方法,下面这种方法是不建议的:
@Entitypublic class Customer implements Serializable { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="CUST_ID") public Set<Ticket> getTickets() { ...}@Entitypublic class Ticket implements Serializable { ... //no bidir}这种方法就是在对方的表中添加一个外键关联。
2.3.3 使用表关联建立单向一对多关系
在单向一对多关联中,下面的方法才是推荐使用的方法。
你可以在“一”和“多”之间建立一张关联表。
@Entity()public class Trainer { @OneToMany @AssociationTable( table=@Table(name="TrainedMonkeys"), joinColumns = { @JoinColumn( name="trainer_id") }, inverseJoinColumns = @JoinColumn( name="monkey_id") ) public Set<Monkey> getTrainedMonkeys() { ...}@Entitypublic class Monkey { ... //no bidir}你可以看到,在“一”这一端,你需要定义关联表的信息:关联表的名称,关联表的外键(指向“一”的外键),关联表的反向外键(指向“多”的外键)。
2.3.4 缺省的一对多映射
如果你指定一个集合对象为一对多关联,但是却没有任何物理数据库表方面的描述,那么默认的情况就是使用关联表的方式,也就是说Hibernate将会给你自己建立关联表。而且关联表的名称是“一”端表名称+下划线+“多”端的表名;关联表对“一”表的外键是“一”表的名称+下划线+“一”表的主键名称;关联表对“多”端的外键就是“一”表的属性名称+下划线+“多”端的主键名称。举个例子:
@Entity()public class Trainer { @OneToMany public Set<Tiger> getTrainedTigers() { ...}@Entitypublic class Tiger { ... //no bidir}上述例子中,建立的关联表名称为“Trainer_Tiger”,到Trainer的外键是“trainer_id”,到Tiger的外键是“trainedTigers_id”。