(1)
簡介:
在過去幾年裡,Hibernate不斷發展,幾乎成為Java資料庫持久性的事實标準。它非常強大、靈活,而且具備了優異的性能。在本文中,我們将了解如何使用Java 5 注釋來簡化Hibernate代碼,并使持久層的編碼過程變得更為輕松。
傳統上,Hibernate的配置依賴于外部 XML 檔案:資料庫映射被定義為一組 XML 映射檔案,并且在啟動時進行加載。
在最近釋出的幾個Hibernate版本中,出現了一種基于 Java 5 注釋的更為巧妙的新方法。借助新的 Hibernate Annotation 庫,即可一次性地配置設定所有舊映射檔案——一切都會按照您的想法來定義——注釋直接嵌入到您的Java 類中,并提供一種強大及靈活的方法來聲明持久性映射。 即利用hibernate注解後,可不用定義持久化類對應的*.hbm.xml檔案,直接以注解方式寫入在持久化類中來實作。 Hibernate annotation使用了ejb JPA的注解,是以,下面安裝配置hibernate annotation環境時,需要導入ejb的包。許多網上的資料都是jpa hibernate annotation方面的資料。 (2)
安裝 Hibernate Annotation
第一步,
環境與jar包:
要使用 Hibernate Annotation,您至少需要具備 Hibernate 3.2和Java 5。可以從 Hibernate 站點下載下傳 Hibernate 3.2 和 Hibernate Annotation庫。除了标準的 Hibernate JAR 和依賴項之外,您還需要 Hibernate Annotations .jar 檔案(hibernate-annotations.jar)、Java 持久性 API (lib/ejb3-persistence.jar)。 添加hibernate3.2.jar,hibernate-annotations- 3.3.0.jar,hibernate-commons-annotations.jar和ejb3-persistence.jar 。這樣就可以使用hibernate的annotation了。
如果您正在使用 Maven,隻需要向 POM 檔案添加相應的依賴項即可,如下所示:
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.1.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.2.0.ga</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency> 第二步,
擷取 Hibernate 會話工廠。盡管無需驚天的修改,但這一工作與使用 Hibernate Annotations有所不同。您需要使用 AnnotationConfiguration 類來建立會話工廠:
sessionFactory = new AnnotationConfiguration().buildSessionFactory();
第三步,
盡管通常使用 <mapping> 元素來聲明持久性類,您還是需要在 Hibernate 配置檔案(通常是 hibernate.cfg.xml)中聲明持久性類:
< !DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
" http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="com.onjava.modelplanes.domain.PlaneType"/>
<mapping class="com.onjava.modelplanes.domain.ModelPlane"/>
</session-factory>
</hibernate-configuration>
近期的許多 Java 項目都使用了輕量級的應用架構,例如 Spring。如果您正在使用 Spring 架構,可以使用 AnnotationSessionFactoryBean 類輕松建立一個基于注釋的 Hibernate 會話工廠,如下所示:
< !-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
...
</props>
</property> <!--指明使用标注的實體類-->
<property name="annotatedClasses">
<list>
<value>com.onjava.modelplanes.domain.PlaneType</value>
<value>com.onjava.modelplanes.domain.ModelPlane</value>
...
</list>
</property> <!--當然也可以不使用上面這種指定的方式,而使用包掃描的方式做為替換,推薦這種--> <property name="packagesToScan">
<list>
<value> com.onjava.modelplanes.domain.*</value>
</list>
</property>
< /bean> (3)
hibernate Annotation标簽的使用: [1]
1.帶注釋的持久性類也是普通 POJO,它們隻是具備了持久性注釋的普通 POJO 。 2.事實上,您既可以保持字段的持久性(注釋寫在成員變量之上),也可以保持屬性(注釋寫在getter方法之上)的持久性。 3.常用的hibernate annotation标簽如下: @Entity --注釋聲明該類為持久類。将一個Javabean類聲明為一 個實體的資料庫表映射類,最好實作序列化.此時,預設情況下,所有的類屬性都為映射到資料表的持久性字段.若在類中,添加另外屬性,而非映射來資料庫的, 要用下面的Transient來注解.
@Table(name= "promotion_info") --持久性映射的表(表名="promotion_info)[email protected]是類一級的注解,定義在@Entity下,為實體bean映射表,目錄和schema的名字, 預設為實體bean的類名,不帶包名.
@Id--注釋可以表明哪種屬性是該類中的獨特辨別符(即相當于資料表的主鍵)。
@GeneratedValue --定義自動增長的主鍵的生成政策.
@Transient --将忽略這些字段和屬性,不用持久化到資料庫.适用于,在目前的持久類中,某些屬性不是用于映射到資料表,而是用于其它的業務邏輯需要,這時,須将這些屬性進行transient的注解.否則系統會因映射不到資料表相應字段而出錯.
@Temporal(TemporalType.TIMESTAMP)--聲明時間格式
@Enumerated --聲明枚舉
@Version --聲明添加對樂觀鎖定的支援
@OneToOne --可以建立實體bean之間的一對一的關聯
@OneToMany --可以建立實體bean之間的一對多的關聯
@ManyToOne --可以建立實體bean之間的多對一的關聯
@ManyToMany --可以建立實體bean之間的多對多的關聯
@Formula --一個SQL表達式,這種屬性是隻讀的,不在資料庫生成屬性(可以使用sum、average、max等)
@OrderBy --Many端某個字段排序(List) 1.2
Hibernate 能夠出色地自動生成主鍵。Hibernate/EBJ 3 注釋也可以為主鍵的自動生成提供豐富的支援,允許實作各種政策。
其生成規則由@GeneratedValue設定的.這裡的@id和@GeneratedValue都是JPA的标準用法, JPA提供四種标準用法,由@GeneratedValue的源代碼可以明顯看出.
JPA提供的四種标準用法為TABLE,SEQUENCE,IDENTITY,AUTO.
TABLE:使用一個特定的資料庫表格來儲存主鍵。
SEQUENCE:根據底層資料庫的序列來生成主鍵,條件是資料庫支援序列。
IDENTITY:主鍵由資料庫自動生成(主要是自動增長型)
AUTO:主鍵由程式控制。 在指定主鍵時,如果不指定主鍵生成政策,預設為AUTO。
@Id 相當于 @Id
@GeneratedValue(strategy = GenerationType.AUTO) identity: 使用SQL Server 和 MySQL 的自增字段,這個方法不能放到 Oracle 中,Oracle 不支援自增字段,要設定sequence(MySQL 和 SQL Server 中很常用)。 Oracle就要采用sequence了. 同時,也可采用uuid,native等其它政策.(相關用法,上網查詢) [2] 第一個持久性類
@Entity
@Table(name= "T_MODEL_PLANE")
public class ModelPlane implements Serializable {
@Id
@Column(name= "PLANE_ID")
@GeneratedValue(strategy=GenerationType.AUTO) //注解于屬性中
private Long id;
private String name; //注解寫于getter方法之上.請見下.
//DATE - java.sql.Date
//TIME - java.sql.Time
//TIMESTAMP - java.sql.Timestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name= "start_time")
private Date startTime;
//顯示0 隐藏1
public static enum DisplayType {顯示,隐藏}
@Enumerated(value = EnumType.ORDINAL) //ORDINAL序數
private DisplayType displayType = DisplayType.顯示;
//1.sql語句中的字段和表名都應該和資料庫相應,而不是類中的字段,
//若帶有參數如la.id= id,這個=id才是類中屬性
//2.操作字段一定要用别名
@Formula(select COUNT(la.id) from largess la)
private int count;
//注解于方法中
@Column(name= "PLANE_ID", length=80, nullable= true) //較詳細定義
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
其它的setter,getter省略......
}
該内容将映射到下表中:
CREATE TABLE T_MODEL_PLANE
(
PLANE_ID long,
PLANE_NAME varchar
其它字段省略...
) 預設情況下,Hibernate 會将持久類以比對的名稱映射到表和字段中。例如,下例中,若不用注解,則會映射到如下一表中:
CREATE TABLE MODELPLANE
(
ID long,
NAME varchar 其它字段省略...
) [3]
一對多注解: 1. 在一對多注解中,會用到: "一"方:
@OneToMany --> mappedBy:"多"方的關聯屬性 (被控方)
"多"方:
@ManyToOne --> @JoinColumn,"多"方定義的外鍵字段. 如資料表定義外鍵如下: FOREIGN KEY (classid) REFERENCES classes(id) 則: @JoinColumn(name= "classid") 2. 在雙向關聯中,有且僅有一端作為主體(owner)端存在:主體端負責維護聯接列(即更新),對于不需要維護這種關系的從表則通過mappedNy屬性進行聲明。mappedBy的值指向另一主體的關聯屬性。例子中,mappedBy的值為classes。 附加說明: mappedBy相當于過去的inverse="true".
inverse=false的side(side其實是指inverse=false所位于的class元素)端有責任維護關系,而inverse=true端無須維護這些關系。 3. cascade與fetch使用說明: Cascade CascadeType.PERSIST (級聯建立)
CascadeType.REMOVE (級聯删除)
CascadeType.REFRESH (級聯重新整理)
CascadeType.MERGE (級聯更新)中選擇一個或多個。
CascadeType.ALL fetch屬性: 關聯關系擷取方式,即是否采用延時加載。
LAZY(預設值)采用延時加載,查詢資料時,不一起查詢關聯對象的資料。而是當通路關聯對象時(如:getStudnets()時)才觸發相應的查詢操作,擷取關聯對象資料。
EAGER:是在查詢資料時,也直接一起擷取關聯對象的資料。 package oneToMany;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name= "classes")
public class Classes implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
@OneToMany(cascade=CascadeType.ALL,mappedBy= "classes")
private Set<Student> students;
//getter,setter省略
}
package oneToMany;
import javax.persistence.*;
@Entity
@Table(name= "student")
public class Student implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int sid;
private String sname;
//若有多個cascade,可以是:{CascadeType.PERSIST,CascadeType.MERGE}
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name= "classid") //student類中對應外鍵的屬性:classid
private Classes classes;
//getter,setter省略
}
public class TestOneToMany {
public static void main(String[] args) throws SQLException
{
try
{
SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
Classes classes= new Classes();
classes.setName( "access");
Student st1= new Student();
st1.setSname( "jason");
st1.setClasses(classes);
session.save(st1);
Student st2= new Student();
st2.setSname( "hwj");
st2.setClasses(classes);
session.save(st2);
tx.commit(); // Student st1=new Student();
// st1.setSname("jason");
// session.save(st1);
//
// Student st2=new Student();
// st2.setSname("hwj");
// session.save(st2);
//
// Set<Student> students=new HashSet<Student>();
// students.add(st1);
// students.add(st2);
//
// Classes classes=new Classes();
// classes.setName("access");
// classes.setStudents(students);
// session.save(classes);
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
} [4]
多對多注解: