2016-09-23 70 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