Hibernate升级后注解方式的对象关系映射

我要说的升级指的是我实际中遇到的,由于我之前的项目中Hibernate是3.3.2版本的,那时关于Annotation注解方式的对象关系映射得依赖这么几个包:

 

  hibernate-annotations.jar,

  ejb3-persistence.jar

  hibernate-commons-annotations.jar

所以之前的项目如果更换为3.5.3版本后(当前最新发布的最终版本是3.6.0),那么这三个依赖包都会没有了,取而代之的是

\hibernate-distribution-3.6.0.Final\lib\jpa\hibernate-jpa-2.0-api-1.0.0.Final.jar

也就是说这个hibernate-jpa-2.0-api-1.0.0.Final.jar能够代替上面的三个包的作用

 

先回顾下一个简单的注解方式的例子



 

User.java

 

Java代码  收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.test;  
  2.   
  3. import javax.persistence.Column;  
  4. import javax.persistence.Entity;  
  5. import javax.persistence.GeneratedValue;  
  6. import javax.persistence.GenerationType;  
  7. import javax.persistence.Id;  
  8. import javax.persistence.Table;  
  9.   
  10. @Entity  
  11. @Table(name = "user")  
  12. // 非必要,在表格名称与类别名称不同时使用  
  13. public class User {  
  14.     @Id  
  15.     @GeneratedValue(strategy = GenerationType.AUTO)  
  16.     private Integer id;  
  17.   
  18.     @Column(name = "name")  
  19.     // 非必要,在字段名称与属性名称不同时使用  
  20.     private String name;  
  21.   
  22.     @Column(name = "age")  
  23.     private Integer age; // 非必要,在字段名称与属性名称不同时使用  
  24.   
  25.     // 必须要有一个预设的建构方法  
  26.     // 以使得Hibernate可以使用Constructor.newInstance()建立对象  
  27.     public User() {  
  28.     }  
  29.   
  30.     public Integer getId() {  
  31.         return id;  
  32.     }  
  33.   
  34.     public void setId(Integer id) {  
  35.         this.id = id;  
  36.     }  
  37.   
  38.     public String getName() {  
  39.         return name;  
  40.     }  
  41.   
  42.     public void setName(String name) {  
  43.         this.name = name;  
  44.     }  
  45.   
  46.     public Integer getAge() {  
  47.         return age;  
  48.     }  
  49.   
  50.     public void setAge(Integer age) {  
  51.         this.age = age;  
  52.     }  
  53. }  
  54. </span>  

Category.java

 

Java代码  收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.test;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import javax.persistence.CascadeType;  
  8. import javax.persistence.Entity;  
  9. import javax.persistence.FetchType;  
  10. import javax.persistence.GeneratedValue;  
  11. import javax.persistence.Id;  
  12. import javax.persistence.JoinColumn;  
  13. import javax.persistence.ManyToOne;  
  14. import javax.persistence.OneToMany;  
  15. import javax.persistence.Table;  
  16. import javax.persistence.Version;  
  17.   
  18.   
  19.   
  20. /** 
  21.  * 产品类别 
  22.  * 
  23.  */  
  24. @Entity  
  25. @Table(name="category")  
  26. public class Category implements Serializable{  
  27.     private static final long serialVersionUID = -3942148673242309324L;  
  28.     @Id  
  29.     @GeneratedValue  
  30.     private Integer id;  
  31.     @Version  
  32.     private Integer version;  
  33.     private String name;  
  34.     private String description;  
  35.     private String path;  //分类路径  
  36.   
  37.     //Category 自身双向多对一   
  38.     @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})  
  39.     private Category parent;  
  40.       
  41.     //Category 自身双向一对多   
  42.     @OneToMany(mappedBy="parent",fetch=FetchType.EAGER,cascade=CascadeType.ALL)  
  43.     @JoinColumn(name="parent_id")  
  44.     private List<Category> child = new ArrayList<Category>();  
  45.       
  46.       
  47.     public Integer getId() {  
  48.         return id;  
  49.     }  
  50.     public void setId(Integer id) {  
  51.         this.id = id;  
  52.     }  
  53.     public String getName() {  
  54.         return name;  
  55.     }  
  56.     public void setName(String name) {  
  57.         this.name = name;  
  58.     }  
  59.     public String getDescription() {  
  60.         return description;  
  61.     }  
  62.     public void setDescription(String description) {  
  63.         this.description = description;  
  64.     }  
  65.     public Category getParent() {  
  66.         return parent;  
  67.     }  
  68.     public void setParent(Category parent) {  
  69.         this.parent = parent;  
  70.     }  
  71.     public List<Category> getChild() {  
  72.         return child;  
  73.     }  
  74.     public void setChild(List<Category> child) {  
  75.         this.child = child;  
  76.     }  
  77.     public Integer getVersion() {  
  78.         return version;  
  79.     }  
  80.       
  81.     @SuppressWarnings("unused")  
  82.     private void setVersion(Integer version) {  
  83.         this.version = version;  
  84.     }  
  85.     public String getPath() {  
  86.         return path;  
  87.     }  
  88.     public void setPath(String path) {  
  89.         this.path = path;  
  90.     }  
  91. }</span>  

 hibernate.cfg.xml

 

Java代码  收藏代码
  1. <span style="font-size: large;"><?xml version="1.0" encoding="utf-8" ?>  
  2. <!DOCTYPE hibernate-configuration PUBLIC  
  3.     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
  5.   
  6. <hibernate-configuration>  
  7. <session-factory>  
  8.        <!-- 显示实际操作数据库时的SQL -->   
  9.         <property name="show_sql">true</property>   
  10.         <!-- SQL方言,这边设定的是MySQL -->   
  11.         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>   
  12.         <!-- JDBC驱动程序 -->   
  13.         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>   
  14.         <!-- JDBC URL -->   
  15.         <property name="connection.url">jdbc:mysql:///test</property>   
  16.         <!-- 数据库使用者 -->   
  17.         <property name="connection.username">root</property>   
  18.         <!-- 数据库密码 -->   
  19.         <property name="connection.password">root</property>   
  20.         <property name="default_batch_fetch_size">10</property>  
  21.         <property name="hibernate.current_session_context_class">thread</property>  
  22.         <property name="show_sql">true</property>  
  23.         <property name="format_sql">true</property>  
  24.         <property name="hbm2ddl.auto">update</property>  
  25.         <!-- 以下设置对象与数据库表格映像类别 -->  
  26.         <mapping class="com.javacrazyer.test.User"/>  
  27.         <mapping class="com.javacrazyer.test.Category"/>    
  28. </session-factory>  
  29. </hibernate-configuration></span>  

Hibernate工具类

 

Java代码  收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.common;  
  2.   
  3. import org.hibernate.Session;  
  4. import org.hibernate.SessionFactory;  
  5. import org.hibernate.cfg.AnnotationConfiguration;  
  6.   
  7. /** 
  8.  * Hibernate工具类 
  9.  *  
  10.  */  
  11. public class HibernateUtil {  
  12.     private static final SessionFactory factory;  
  13.       
  14.     private HibernateUtil(){}  
  15.       
  16.     static{  
  17.         //加载Hibernate全局配置文件,根据配置信息创建SessionFactory工厂实例  
  18.         factory = new AnnotationConfiguration().configure().buildSessionFactory();  
  19.     }  
  20.       
  21.     public static SessionFactory getSessionFactory(){  
  22.         return factory;  
  23.     }  
  24.       
  25.     /** 
  26.      * 本方法用来获取当前线程上绑定的Session实例 
  27.      * 注意hibernate全局配置文件中,如果使用是JDBC事务,添加如下配置:<br/> 
  28.      * <property name="hibernate.current_session_context_class">thread</property> 
  29.      * @return 
  30.      */  
  31.     public static Session getSession(){  
  32.         return factory.getCurrentSession();  
  33.     }  
  34. }  
  35. </span>  

 

测试类

 

Java代码  收藏代码
  1. <span style="font-size: large;">package com.javacrazyer.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.hibernate.Session;  
  7. import org.hibernate.SessionFactory;  
  8. import org.hibernate.Transaction;  
  9. import org.junit.BeforeClass;  
  10. import org.junit.Test;  
  11.   
  12. import com.javacrazyer.common.HibernateUtil;  
  13.   
  14.   
  15. public class MyTest {  
  16.     private static SessionFactory sf;  
  17.   
  18.     @BeforeClass  
  19.     public static void init() {  
  20.         sf = HibernateUtil.getSessionFactory();  
  21.     }  
  22.   
  23.     @Test  
  24.     public void useradd() {  
  25.         User user = new User();  
  26.         user.setName("caterpillar");  
  27.         user.setAge(new Integer(30));  
  28.   
  29.         // 开启Session,相当于开启JDBC的Connection  
  30.         Session session = sf.getCurrentSession();  
  31.         // Transaction表示一组会话操作  
  32.         Transaction tx = session.beginTransaction();  
  33.         // 将对象映像至数据库表格中储存  
  34.         session.save(user);  
  35.         tx.commit();  
  36.   
  37.         System.out.println("新增资料OK!请先用MySQL观看结果!");  
  38.     }  
  39.       
  40.     @Test  
  41.     public void categoryadd(){  
  42.         Category category=new Category();  
  43.         category.setName("类别1");  
  44.           
  45.         Category category1=new Category();  
  46.         category1.setName("类别1-01");  
  47.         category1.setParent(category);  
  48.           
  49.         Category category2=new Category();  
  50.         category2.setName("类别1-02");  
  51.         category2.setParent(category);  
  52.           
  53.         List<Category> childs=new ArrayList<Category>();  
  54.         childs.add(category1);  
  55.         childs.add(category2);  
  56.         category.setChild(childs);  
  57.         Session session = sf.getCurrentSession();  
  58.         // Transaction表示一组会话操作  
  59.         Transaction tx = session.beginTransaction();  
  60.         session.persist(category);  
  61.         tx.commit();  
  62.     }  
  63.       
  64.       
  65.   
  66. }  
  67. </span>  

 

 

对于User的持久化操作相当顺利,这个升级过程是成功的。

但是对于Category的升级就没那么容易了,如果不细心发现的话,总是报

 

Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn

或者是Unrooted Test之类的错误
 
错误发生在下面这些代码中
@OneToMany(mappedBy="parent",fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name="parent_id")
private List<Category> child = new ArrayList<Category>();
后来发现在3.5.3版本中@JoinColumn与mappingBy是互斥的,之前在hibernate.3.3.2中都是正确无误的,也就是hibernate.3.3.2允许这两个互相存在。所以呢,如果升级到hibernate3.5.3想测试成功的话,mappBy="parent",就应该去掉,正确的配置应该是这样
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name="parent_id")
private List<Category> child = new ArrayList<Category>();
 
索性将mappingBy再温习下
a) 只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性,ManyToOne不存在该属性;
b) mappedBy标签一定是定义在the owned side(被拥有方的),他指向the owning side(拥有方);
c) mappedBy的含义,应该理解为,拥有方能够自动维护 跟被拥有方的关系;
   当然,如果从被拥有方,通过手工强行来维护拥有方的关系也是可以做到的。
d) mappedBy跟JoinColumn/JoinTable总是处于互斥的一方,可以理解为正是由于拥有方的关联被拥有方的字段存在,拥有方才拥有了被 拥有方。mappedBy这方定义的JoinColumn/JoinTable总是失效的,不会建立对应的字段或者表
posted @ 2012-12-28 19:25  eggbucket  阅读(853)  评论(0编辑  收藏  举报