(九)Hibernate之有關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總是失效的,不會建立對應的字段或者表
發佈了7 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章