2016-09-23 69 views
1

想象一下,我有一個MySQL數據庫,其中有兩個表patientmedicine。我已經在下面顯示了他們的列。關係處理:Hibernate vs JDBC

患者

idPatient (int) (primary key) 
first_name (varchar) 
last_name (varchar) 

醫學

idMedicine (int) (primary key) 
idPatient (int) (foreign key) 
drug_name (varchar) 

請注意Medicine表確實有Patient表的foriegn關鍵。現在

,如果我用純JDBC,我將做以下爲MedicinePatient表創建一個bean

PatientBean

public class PatientBean 
{ 
    private int idPatient; 
    private String first_name; 
    private String last_name; 

    public void setIdPatient(int idPatient) 
    { 
     this.idPatient = idPatient; 
    } 

    public int getIdPatient() 
    { 
     return idPatient; 
    } 

    public void setFirstName(String first_name) 
    { 
     this.first_name = first_name; 
    } 

    public String getFirstName() 
    { 
     return first_name; 
    } 

    public void setLastName(String last_name) 
    { 
     this.last_name = last_name; 
    } 

    public String getLastName() 
    { 
     return last_name; 
    } 

} 

`MedicineBean` class 

public class MedicineBean 
{ 
    private int idMedicine; 
    private int idPatient; 
    private String drug_name; 

    public void setIdMedicine(int idMedicine) 
    { 
     this.idMedicine = idMedicine; 
    } 

    public int getIdMedicine() 
    { 
     return idMedicine; 
    } 

    public void setIdPatient(int idPatient) 
    { 
     this.idPatient = idPatient; 
    } 

    public int getIdPatient() 
    { 
     return idPatient; 
    } 

    public void setDrugName(String drug_name) 
    { 
     this.drug_name = drug_name; 
    } 

    public String getDrugName() 
    { 
     return drug_name; 
    } 

} 

但是如果我反向設計我的數據庫休眠使用像NetBeans這樣的工具將生成POJO文件,爲Hibernate映射等,我可以期待類似下面的內容。

PatientBean

public class PatientBean 
    { 
     private int idPatient; 
     private String first_name; 
     private String last_name; 
    private MedicineBean medicineBean; 

     public void setIdPatient(int idPatient) 
     { 
      this.idPatient = idPatient; 
     } 

     public int getIdPatient() 
     { 
      return idPatient; 
     } 

     public void setFirstName(String first_name) 
     { 
      this.first_name = first_name; 
     } 

     public String getFirstName() 
     { 
      return first_name; 
     } 

     public void setLastName(String last_name) 
     { 
      this.last_name = last_name; 
     } 

     public String getLastName() 
     { 
      return last_name; 
     } 

    public void setMedicineBean(String medicineBean) 
     { 
      this.medicineBean = medicineBean; 
     } 

     public String getMedicineBean() 
     { 
      return medicineBean; 
     } 
    } 

MedicineBean

public class MedicineBean 
    { 
     private int idMedicine; 
     private int idPatient; 
     private String drug_name; 
    private Set<PatientBean> patients = new HashSet<PatientBean>(0); 

     public void setIdMedicine(int idMedicine) 
     { 
      this.idMedicine = idMedicine; 
     } 

     public int getIdMedicine() 
     { 
      return idMedicine; 
     } 

     public void setIdPatient(int idPatient) 
     { 
      this.idPatient = idPatient; 
     } 

     public int getIdPatient() 
     { 
      return idPatient; 
     } 

     public void setDrugName(String drug_name) 
     { 
      this.drug_name = drug_name; 
     } 

     public String getDrugName() 
     { 
      return drug_name; 
     } 

    public void setPatients(Set<PatientBean>patients) 
    { 
     this.patients = patients; 
    } 

    public Set<PatientBean> getPatients() 
    { 
     return patients; 
    } 

    } 

不僅如此,Hibernate也將映射的關係式(一對一,一對多,多對一)在xml文件裏面。但是在JDBC中我們根本不關心它們,它們只是用相同的方式處理的外鍵。

所以我的問題是,爲什麼這種差異?我相信Hibernate所做的大部分操作都是無用的,只是使用CPU。例如,當我們調用getAllMedicines()方法時,試圖檢索Patient表中的patients列表。在99%的情況下,我們只需要所有藥物而不是患者名單,如果我們需要我們可以加入並得到它!

那麼背後的原因是什麼?否則,我們是否也應該爲JDBC保持相同的行爲?

+0

「患者」列表通常會被延遲加載,這意味着它只會在需要時讀取數據。第二種方式包含您的數據,正如您通常將其寫入面向對象程序 –

+0

@ScaryWombat:是的,我知道。我的問題是爲什麼我們在JDBC中不這樣做?我看到它簡直沒用。 –

+1

您不在JDBC中執行此操作的唯一原因是您*不在JDBC中執行此操作。 *您完全可以完全控制自己想要做什麼,所以您可以通過用PatientBean病人替換MedicineBean的'int idPatient',並向PatientBean添加一個'List 藥物「來完成。根據它們的使用方式,這是另一種方式。 – Andreas

回答

0

我不認爲用冬眠你會失去完全控制,因爲你害怕。

主要區別在於hibernate會在你的代碼和jdbc之間添加一個額外的層。該層可以非常簡潔:您可以隨時在休眠模式中隨時使用jdbc。所以你不會失去任何控制。

更難的部分是瞭解hibernate是如何工作的,以便您可以使用其更高級別的api並知道hibernate將如何將其轉換爲jdbc。這有點複雜,因爲orm映射是一個複雜的主題。多次閱讀參考文檔,確切瞭解hibernate可以做什麼,以及他們推薦做什麼和不做什麼,這是一個很好的起點。其餘的將來自使用休眠的經驗。

對於你的例子,你說休眠映射關係,但事實並非如此:你的逆向工程工具做到了。你可以自由地不映射關係和映射,而只需要外鍵基本類型(比如一個Long,如果id是一個數字)。

至於負載的東西。如果您希望始終加載@OneToMany,只需使用FetchType.EAGER對其進行註釋即可。 @*ToMany默認情況下協會是懶惰的(以避免加載太多數據),但另一方面,@*ToOne協會默認爲EAGER

這可以在實體級配置,使其成爲查詢的默認行爲,但可以爲每個查詢重載。

你看?你不失去控制,你只需要瞭解hibernate api如何轉換成jdbc。

除了提升到休眠團隊時修復的bug之外,hibernate的性能影響並不大。在應用程序的性能關鍵部分,您總是可以選擇使用休眠開銷爲0的jdbc。

您從使用hibernate獲得什麼?根據我的經驗,在實體模型/數據庫模型中重構要容易得多,因爲您更改了hibernate映射,並且由hibernate生成的所有查詢也會自動更改。您只需更新您手寫的自定義查詢(SQL/HQL/Criteria)。

從我的經驗(10年使用休眠)在幾百個表(其中一些超過10B行),幾個TB的數據庫,我不想回到普通的jdbc,這並不意味着我不會當它是完美的工具時不會使用它,但它就像我編寫的orm代碼的1%或2%。

希望有所幫助。

編輯:如果你使用hibernate和spring,看看spring-jdbc,它在jdbc上添加了一個不錯的圖層。在那裏,你幾乎不需要閱讀文檔:你直接意識到它將如何被轉換爲jdbc,但它帶來了很多實用工具,可以減少很多直接使用jdbc的樣板(例如異常處理關閉ResultsetPreparedStatement,將ResultSet轉換爲DTO列表等)。

當然,hibernate和spring-jdbc可以在同一個應用程序中使用。他們只需要配置爲使用相同的事務層,並且在同一個tx中使用時應小心。

+0

謝謝你的回覆。不,我不在Spring中使用Hibernate,我正在構建一個'REST API'。我不同意你在這裏 - 「如果你想永遠有一個@OneToMany加載,只需使用FetchType.EAGER'註釋它將是一個巨大的開銷。」無論如何,你的意思是我可以使用外鍵像'idPatient'就像在Hibernate中一樣,不需要將其設置爲「SET」或一個完整的bean?那我必須改變關聯的XML不是嗎?我沒有使用註釋。 –

+0

我說的立場也爲hbm映射。你爲什麼說這是一個巨大的開銷?爲了加載父實體,hibernate將觸發2個查詢:一個加載父(通過id,一行,不應該很重),一個用於你感興趣的子集。你不需要父實體?只需創建一個Criteria/HQL/SQL來加載parent_id = parent.id的子實體(並且不要忘記將ManyToOne標記爲LAZY)。 hbm映射文件需要反映兩件事情:數據庫模型以及如何從Java代碼訪問實體。僅供參考,hbm文件已被棄用。 – Thierry

+0

我從高層的角度回答了你的問題,因爲在我看來,你需要更多的全局洞察力而不是休眠的精確部分的答案。如果不是這種情況,請向您的問題添加表格的數據庫模型,hbm映射文件,您希望hibernate生成的sql查詢以及您的hibernate加載代碼,然後我們將看看如何修改映射和休眠代碼來獲得你想要的。 – Thierry