Hibernate Annotation (Hibernate 注解)

时间:2021-01-01 18:50:19

简介:

传统上,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:)
at org.junit.runners.BlockJUnit4ClassRunner$.runReflectiveCall(BlockJUnit4ClassRunner.java:)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:)
at org.junit.runners.ParentRunner$.run(ParentRunner.java:)
at org.junit.runners.ParentRunner$.schedule(ParentRunner.java:)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:)
at org.junit.runners.ParentRunner.access$(ParentRunner.java:)
at org.junit.runners.ParentRunner$.evaluate(ParentRunner.java:)
at org.junit.runners.ParentRunner.run(ParentRunner.java:)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:)
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:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory$.getObject(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at com.lizhou.action.test.TestAction.<clinit>(TestAction.java:)
... 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:)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:)
at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:)
at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:)
at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:)
... 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,会冲突!