Hibernate Annotation (Hibernate 注解)


簡介: 

傳統上,Hibernate的配置依賴於外部 XML 文件:數據庫映射被定義為一組 XML 映射文件,並且在啟動時進行加載。

然而現在借助新的 Hibernate   Annotation 庫,即可一次性地分配所有舊映射文件——一切都會按照您的想法來定義——注釋直接嵌入到您的Java類中,並提供一種強大及靈活的方法來聲明持久性映射。即利用hibernate注解后,可不用定義持久化類對應的*.hbm.xml文件,直接以注解方式寫入在持久化類中來實現。

Hibernate annotation使用了ejb JPA的注解,所以,下面安裝配置hibernate annotation環境時,需要導入ejb的包。

配置:

(1)安裝 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)。

(2)添加hibernate3.2.jar,hibernate-annotations-  3.3.0.jar,hibernate-commons-annotations.jar和ejb3-persistence.jar   。這樣就可以使用hibernate的annotation了。
(3) 如果您正在使用 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>
 
(4)hibernate annotation標簽的使用
      【1】帶注釋的持久化類也是普通POJO,它們只是具有持久性注釋的普通POJO。
      【2】事實上你既可以保持字段(注釋寫在成員變量之上)的持久性,也可以保持屬性(注釋寫在getter方法之上)的持久性。
      【3】常用的Hibernate annotation標簽如下:  
             @Entity                    --注釋聲明該類為持久類。將一個Javabean類聲明為一  個實體的數據庫表映射類,最好實現序列化.此時,默認情況下,所有的類屬性都為映射到數據表的持久性字段.若在類中,添加另外屬性,而非映射來數據庫的,  要用下面的Transient來注解.
             @Table(name="promotion_info")      --持久性映射的表(表名="promotion_info).@Table是類一級的注解,定義在@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)
        【4】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等其它策略。
(5)
onetomany示例:
@Entity
@Table(name = "Dept")

public class Dept {
    @Id
    @GeneratedValue
    /*
       對於oracle想使用各自的Sequence,設置如下:
       @GeneratedValue(strategy =GenerationType.AUTO,generator="PROMOTION_SEQ")
       @SequenceGenerator(name="PROMOTION_SEQ",sequenceName="PROMOTION_SEQ")
       另外:
        對於自動增長后,在數據表中的相應字段,要設置字段為auto_increment.
    */
    private Integer deptno;
    @Column
    private String deptname;
    @OneToMany(mappedBy="dept")
//mappedBy 屬性主要針對外鍵而言,與之對應的是.xml中的inverse屬性
//mappedBy="dept" 是把維護權交給多的一方
@LazyCollection(LazyCollectionOption.FALSE)
private Set<Emp> emps=new HashSet<Emp>();
public Integer getDeptno() { return deptno; }
public void setDeptno(Integer deptno) { this.deptno = deptno; }
public String getDeptname() { return deptname; }
public void setDeptname(String deptname) { this.deptname = deptname; }
public Set<Emp> getEmps() { return emps; }
public void setEmps(Set<Emp> emps) { this.emps = emps; } }

默認情況下,Hibernate 會將持久類以匹配的名稱映射到表和字段中。

@Entity
@Table(name = "Emp")
public class Emp {
    @Id
    @GeneratedValue
    private Integer empno;
    @Column
    private String ename;
//如果有多個cascade,可以是{CascadeType.PERSIST,CascadeType.MERGE} @ManyToOne(cascade
= {CascadeType.ALL}) @JoinColumn(name = "deptno")//dept類對應外鍵的屬性:deptno private Dept dept; public Integer getEmpno() { return empno; } public void setEmpno(Integer empno) { this.empno = empno; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } }

在hibernate.cfg.xml中的

<session-factory>

    .....

   <mapping class="cn.onetomanydouble.entity.Dept"/>  

   <mapping class="cn.onetomanydouble.entity.Emp"/>

</session-factory>

這里遇到一個問題:如果配置mappedBy屬性的同時加上@JoinColumn會拋出異常,所以不能同時使用@JoinColumn和mappedBy;因為@JoinColumn本身就是自己來維護外鍵,和mappedBy沖突了。--->>>希望大牛可以再詳細的解說下!

拋出的異常如下:

java.lang.ExceptionInInitializerError
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:217)
    at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: com.lizhou.entity.test.Department.employeeList
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:684)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.lizhou.action.test.TestAction.<clinit>(TestAction.java:26)
    ... 22 more
Caused by: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: com.lizhou.entity.test.Department.employeeList
    at org.hibernate.cfg.annotations.CollectionBinder.bind(CollectionBinder.java:493)
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2156)
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:963)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:796)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3788)
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3742)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:343)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:431)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:416)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 34 more

在這里再說一下,如果先保存員工后保存部門,會多出四條update語句。

Hibernate: insert into emp (deptno, ename, empno) values (?, ?, ?)
Hibernate: insert into emp (deptno, ename, empno) values (?, ?, ?)
Hibernate: insert into dept(dname) values (?)
Hibernate: update emp set deptno=?, ename=? ,empno=? where id=?
Hibernate: update emp set deptno=?, ename=? ,empno=?  where id=?
Hibernate: update emp set deptno=?  ,empno=? where id=?
Hibernate: update emp set deptno=?  ,empno=? where id=?

總結:mappedBy屬性跟xml配置文件里的inverse一樣。在一對多或一對一的關系映射中,如果不表明mappedBy屬性,默認是由本方維護外鍵。但如果兩方都由本方來維護的話,會多出一些update語句,性能有一定的損耗。

解決的辦法就是在一的一方配置上mappedBy屬性,將維護權交給多的一方來維護,就不會有update語句了。

注意,配了mappedBy屬性后,不要再有@JoinColumn,會沖突!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM