想象一下,我有一个包含2个表patient
和medicine
的MySQL数据库。我在下面显示了他们的专栏。
病人
idPatient (int) (primary key)
first_name (varchar)
last_name (varchar)
医学
idMedicine (int) (primary key)
idPatient (int) (foreign key)
drug_name (varchar)
请注意,Medicine
表的{for}关键字为Patient
。
现在,如果我使用纯JDBC,我将执行以下操作为Medicine
和Patient
表创建一个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这样的工具对hibernate进行逆向工程,它会为Hibernate生成POJO文件,映射等,我可以期待下面的内容。
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。例如,当我们调用patients
方法时,尝试检索Patient
表中的getAllMedicines()
列表。在99%的情况下,我们只需要所有药物而不是患者名单,如果我们需要,我们可以加入并获得它!
那背后的原因是什么?或者我们也应该为JDBC保持相同的行为吗?
答案 0 :(得分:0)
我不认为在休眠时你会因为害怕而失去完全的控制权。
主要区别在于hibernate会在你的代码和jdbc之间添加一个额外的层。这个层可以很薄:你可以随时选择在hibernate 中使用jdbc 。所以你没有失去任何控制。
更难的部分是了解hibernate如何工作,以便您可以使用其更高级别的api并知道hibernate将如何将其转换为jdbc。这有点复杂,因为orm映射是一个复杂的主题。多次阅读参考文档,确切了解hibernate可以做什么,以及他们建议做什么和不做什么,都是一个很好的起点。剩下的将来自使用hibernate的经验。
对于你的例子,你说hibernate地图关系,但事实并非如此:你的逆向工程工具做到了。您可以自由地不映射关系和映射而只是映射外键基本类型(如果id是数字,则为Long)。
关于东西的装载。如果您希望始终加载@OneToMany,只需使用FetchType.EAGER
进行注释即可。默认情况下,@*ToMany
关联是惰性的(以避免加载太多数据),但另一方面,@*ToOne
关联默认为EAGER
。
这可以在实体级别配置,使其成为查询的默认行为,但可以为每个查询重载。
你知道吗?你不会失去控制,你只需要了解hibernate api如何转换为jdbc。除了在提升到hibernate团队时修复的bug之外,hibernate对性能的影响并不大。在应用程序的性能关键部分,您始终可以选择使用jdbc,其中hibernate开销为0.
使用hibernate可以获得什么?根据我的经验,重构实体模型/数据库模型要容易得多,因为你改变了hibernate映射,而hibernate生成的所有查询也会自动改变。您只需更新您手写的自定义查询(SQL / HQL / Criteria)。
根据我的经验(使用hibernate 10年)在数百个表(其中一些超过10B行),数TB的数据库,我不想回到普通的jdbc,这并不意味着我不要当它是完美的工具时使用它,但它就像我编写的orm代码的1%或2%。
希望有所帮助。
编辑:如果你正在使用spring的hibernate,请看一下spring-jdbc,它在jdbc周围增加了一个很好的层。在那里,你几乎不需要阅读文档:你直接认识到如何将它转换为jdbc,但它带来了许多实用工具,可以减少很多直接使用jdbc的样板(比如关闭{{1}的异常处理}和Resultset
,将PreparedStatement
转换为DTO列表等。)
当然,hibernate和spring-jdbc可以在同一个应用程序中使用。它们只需配置为使用相同的事务层,并且在同一个tx中使用时要小心。