Hibernate Annotation筆記 Hibernate Annotation筆記 Hibernate Annotation筆記

2010-04-06 22:20:51 标簽: java 筆記 Hibernate Annotation [ 推送到技術圈 ]
(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> </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] 多對多注解: 在多對多注解中,雙方都采用@ManyToMany. 其中被控方,像一對多注解中設定一樣,也要設定mappedBy. 其中主要方,不像一對多注解那樣,采用@joinColumn,而是采用@joinTable.如下: @JoinTable(name="j_student_course" ,joinColumns={@JoinColumn(name="sid")},inverseJoinColumns={@JoinColumn(name="cid")}) 其中, 如上所說,mappedBy,相當于inverse="true".是以,在@joinTable中的inverseJoinColumns中定義的字段為mappedBy所在類的主鍵. joinColumns定義的字段,就是目前類的主鍵. @Entity @Table(name= "jcourse" ) public class Jcourse { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int cid; private String cname; @ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.LAZY ,mappedBy= "courses" ) private Set<Jstudent> students; //setter,getter省略.... } @Entity @Table(name= "jstudent" ) public class Jstudent { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int sid; private String sname; @ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.EAGER) //inverseJoinColumns中對應的id為以下屬性course的對應id. @JoinTable(name= "j_student_course" ,joinColumns={@JoinColumn(name= "sid" )},inverseJoinColumns={@JoinColumn(name= "cid" )}) private Set<Jcourse> courses; //setter,getter省略.... } public class Test { public static void main(String[] args) { try { SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory(); Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Jcourse course= new Jcourse(); course.setCname( "jason-english" ); session.save(course); //先各自儲存. Jcourse course2= new Jcourse(); course2.setCname( "herry-english" ); session.save(course2); Set<Jcourse> courses= new HashSet<Jcourse>(); courses.add(course); courses.add(course2); Jstudent student= new Jstudent(); student.setSname( "jason" ); student.setCourses(courses); session.save(student); // 要用非mapby定義的類(studet)來作為主者(會控制級聯關系),一對多,多對一也一樣道理. //可以嘗試反過來. tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } } |