• 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,会冲突!

  • 相关阅读:
    JavaScript 监听回车事件
    上下文(Context)和作用域(Scope)
    图解Javascript上下文与作用域
    JavaScript的作用域(Scope)和上下文(Context)
    Table 边框合并(collapse)
    Aspose.Words .NET如何实现文档合并的同页分页显示
    【C#.NET】Http Handler 介绍---(转)
    Oracle无监听程序
    PL/SQL程序设计、流程控制
    ORACLE函数、连接查询、约束
  • 原文地址:https://www.cnblogs.com/wl0000-03/p/6381985.html
Copyright © 2020-2023  润新知