VVL1295

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Hibernate关联映射之我见

  Hibernate的确在一定程度上提高了软件的开发效率,使我们不用写大量基本的sql,能很好地整合缓存(如ehcache),良好的数据库移植性,还有很多人都喜欢用的关联映射(处理主表与从表的级联操作);

  本文讨论的是关联映射的利与弊;

  利:1,EAGER加载;2,级联操作能减少程序员的工作量;

  弊:学习成本大;不灵活;不方便且其实很少用得上;某些操作时存在性能问题;代码不直观(其实有部分也算是学习成本大的结果,因为要付出较大的学习成本才能很好地知道底层到底干了什么);

  这里先讨论弊:

    1,学习成本大(这个比较主观,兴许有的人学习得很轻松

       关联映射需要注解,注解里面有不少的属性,属性的设置就可能影响着底层生成的sql,例如各位看官是否知道@OneToMany的cascade属性值为CascadeType.REMOVE和orphanRemoval=true同样会使得,删除主表记录时会使从表对应的记录也被删除?insertable=false,意味着插入一个主表实体类对象,不能使得从表实体类对象也被插入;updatable=true,Order为主表实体类,orderItem为从表实体类,且未EAGER加载,那么order.setOrderItemList(null)会使得从表对应的记录的外键列字段设为null;如果您知道,说明您好好学习过,那您认为学习成本算大吗?真的很容易就记得很牢吗?(这让我想起了学习C++时,书本上写了运算符的优先级,但我们不应该记这些东西,用括号就好了;而使用关联映射,要时不时看手册,看文档,对比起不用关联映射,在这方面的确比较麻烦,不用关联映射就避免了这种麻烦)

    2,不灵活(比较主观的观点

       采用了关联映射,设置了级联操作,那我们的某些操作就肯定会是级联操作了,但某些业务逻辑是需要级联操作,有些业务逻辑就不需要级联操作,这就是不灵活的体现,那就要改级联操作的设置了,这个机率不大,但业务逻辑是挺难说的;

    3,不方便且其实很少用得上

       查:对于EAGAR加载,很多情况下因为性能问题,是不能EAGAR加载的(很少用得上EAGER加载);

       删:对于级联删除操作,对比起删掉一个实体,大多数时候的删除,是通过根据ID或者某个字段进行删除,这时候就会通过HQL或者SQL语句,而这时候如果直接是删除主表的记录,就会抛出外键约束异常;那么我们就还是只能先删掉从表对应的记录,再删掉主表对应的记录,所以说大多数情况下关联映射的级联删除并不管用,还是要手动处理主表与从表的关系(很少用得上级联删除);

       增:对于非连接表的单向映射,肯定会有性能问题;只能选择链接表或者双向映射来避免性能问题;连接表,不方便;双向映射,由N的一方控制关联关系,先插入主表实体,再设置从表实体的外键属性,再插入从表实体,不方便,看第4点,批量删除时也不能使用这种插入的方式(级联插入不方便);

       改:很多情况下,不需要级联更新的操作,通常是用户修改了主表记录对应的数据,然后只应该修改主表的记录,绝大多数情况下是不需要更新从表记录的,如果硬要级联更新,就必定会有性能问题(更新了不需要更新的记录);而且在LAZY加载的情况下,更新主表记录也不能级联更新从表记录,要再查从表记录,再进行更新,有性能问题(很少用得上级联更新);

    4,某些操作时存在性能问题

       增:批量插入,项目中很可能会有批量插入的操作,因为MySQL不支持batch_size,所以通过batch_size提高批量插入的性能是不可能的;那这种情况下,也只能写SQL用形如“INSERT INTO table (xx,xx) VALUES (xx,xx),(xx,xx)...”进行批量插入(这种情况下,级联插入存在性能问题);

         删:批量删除,如第3点,不能使用级联删除,如果使用级联删除,就必须先查再删,这就存在性能问题(这种情况下,级联删除存在性能问题);

       改:因为MySQL不支持batch_size,所以要提高更新的性能,就只能拼接更新的语句,很明显,关联映射的级联操作办不到(这种情况下,级联更新存在性能问题);

       查:很多情况下,EAGER加载带来性能问题(EAGER加载存在性能问题);

    总结,关联映射的级联操作帮助程序员减轻的工作量是相当有限的,而减轻了工作量,就意味着比较可能会带来性能的降低或者编码的麻烦(同时顾及关联映射注解的属性和多变的业务逻辑是麻烦的,例如如第2点,某些业务逻辑需要级联更新而某些业务不需要级联更新;而且,使用关联映射,程序会比较不直观),弊大于利,即便编码的麻烦能接受,而很多情况下性能的降低是不能接受的;

    我认为应该这样使用Hibernate:使用Hibernate来避免编写基本的数据库操作(就是写泛型BaseDao),使用其缓存(与Spring整合起来也很好用),手动维护主表与从表的关系(代码清晰,且真正控制了底层的SQL,实现较好的数据库操作性能),手动写非基本的SQL(真正控制了底层的SQL,实现较好的数据库操作性能),这样,带来是较为流畅的开发体验,较低的维护成本,较低的开发成本(其中一个原因是降低了学习成本,毕竟项目总可能会有新人维护)。

    补充,又看了看知乎的帖子,的确在很多表有大量主从表关系时,关联映射能省去很多工作量(但同时也带来了性能问题和维护成本增加的问题),我相信会有解决办法,写工具类解决之,我以后有机会就会去写(在省去工作量的同时,保证程序的可读性和应用的性能);

 

    

 

posted on 2016-06-16 11:12  bobo2018  阅读(108)  评论(0)    收藏  举报