天天看點

Hibernate Annotation筆記 Hibernate Annotation筆記

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();        

    }

  }

}