技术分享 HIBERNATE 查看内容

robbin——hibernate与数据库建模

老高 | 发布于 2016-03-31 08:41| 浏览()| 评论() | 收藏() | 点赞() | 打印

摘要: 其实围绕Hibernate的话题,我都已经说过不下30遍,以致于最近两年以来,我对所有Hibernate的问题都不愿意再回应。另外最近一年多来,使用Rails的ActiveRecord,让我对ORM的认识又加深了很多,其实对于那么多争议的问题,最好的解决办法就是自己去实践。对于自己没有去实践过的东西,争是争不出来什么的。

其实围绕Hibernate的话题,我都已经说过不下30遍,以致于最近两年以来,我对所有Hibernate的问题都不愿意再回应。另外最近一年多来,使用Rails的ActiveRecord,让我对ORM的认识又加深了很多,其实对于那么多争议的问题,最好的解决办法就是自己去实践。对于自己没有去实践过的东西,争是争不出来什么的。  

1、以数据库为中心建模 VS 以领域模型为中心建模:  

老开发人员大多倾向于前者,因为比较符合过去的开发习惯,另外他们强调数据库的生命周期大于App  

向我这样的只有几年工作经验的往往会倾向于后者,因为这能更充分发挥ORM的威力,更符合OO,免去很多维护DB的繁琐工作。

数据库设计三大范式如雷贯耳,但作为非科班出身的我直到两个月前竟然都不知道三大范式究竟是什么。那么三大范式是什么?  

第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。  

第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。  

第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A。

两个月前当我购买了一本《MySQL权威指南》,翻到三大范式的定义的时候,我内心巨震,三大范式简单总结一句就是消除冗余,单纯依赖关系。不允许数据库表出现冗余字段,不允许表之间多重依赖,因此符合三大范式设计的数据库模型其实和你按照面向对象思想去建模得到的数据库模型是一样的。  

所以不论你是从数据库为中心建模,还是你以领域模型为中心建模,你应该最终得到一个一致的数据库模型。之所以导致数据库建模和OO建模的不一致,是因此传统的数据库建模从来都是违背三大范式的。而我们在过去经常说的一句话就是:为了数据库查询性能,我们需要多加一些冗余字段,不一定非要遵循三大范式......  

所以不要再说什么数据库设计和面向对象设计导致的数据模型冲突的话,不是他们冲突,是你违背了三大范式,自己制造出来的冲突。  

2、Hibernate VS iBatis/JDBC:  

担心失去对SQL待控制权,导致不能做优化,DBA反对  

Hibernate是在JDBC之上的又一层框架,因此想当然的认为其性能不如iBatis/JDBC(我认为这个结论不成立,因为引入一个ORM层给了我们更多机会去优化性能,比如一二级缓存、lazyload、查询缓存,并且方式更优雅)。参考为什么ORM性能比iBATIS好?  

担心OpenSessionInView模式有性能问题(http://www.iteye.com/topic/17501)  

Hibernate无法应付复杂查询(我认为这不是问题,HQL和criteria查询能力很强,再不济还可以用SQL啊)

JavaEye网站的数据库设计是面向对象为中心的设计,但是拿三大范式来衡量,大部分设计都是吻合的,而我们的数据库缓存命中率在90%左右。缓存服务器的流量是数据库服务器流量的2.5倍之多。事实上我们有很多地方的查询尽量避免join,宁可让他n+1,这样速度反而更快,缓存命中率更高。  

例如我们现在把帖子的内容字段拆分出来,单独放在一个post_texts表里面。这样posts表实际上只有35MB,而post_texts表有1GB。每次显示一个post,都会用主键去load post_text,命中缓冲。不需要查数据库,不需要去碰那个1GB的大表。  

要充分发挥ORM的缓存优势,就必须把表设计的尽量细颗粒度,消除冗余和多重依赖,最终可能是相当多的小表,表之间通过主外键关联,但是关联关系都是单一的。那么这种追求面向对象的数据库模型是非常符合三大范式的。

发表评论(对文章涉及的知识点还有疑问,可以在这里留言,老高看到后会及时回复的。)

表情