精华内容
下载资源
问答
  • 2021-11-02 23:19:56

    现在对hibernate和mybatis做一下对比,便于大家更好的理解和学习,使自己在做项目中更加得心应手。

    第一方面:开发速度的对比

    就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。

    比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求去考虑究竟哪一个更适合项目开发,比如:一个项目中用到的复杂查询基本没有,就是简单的增删改查,这样选择hibernate效率就很快了,因为基本的sql语句已经被封装好了,根本不需要你去写sql语句,这就节省了大量的时间,但是对于一个大型项目,复杂语句较多,这样再去选择hibernate就不是一个太好的选择,选择mybatis就会加快许多,而且语句的管理也比较方便。

    第二方面:开发工作量的对比

    Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。

    第三方面:sql优化方面

    Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。

    Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。

    第四方面:对象管理的对比

    Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。

    换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。
    第五方面:缓存机制

    Hibernate缓存

    Hibernate一级缓存是Session缓存,利用好一级缓存就需要对Session的生命周期进行管理好。
    建议在一个Action操作中使用一个Session。一级缓存需要对Session进行严格管理。
    Hibernate二级缓存是SessionFactory级的缓存。 SessionFactory的缓存分为内置缓存和外置缓存。
    内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。
    外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。**

    MyBatis缓存

    MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。

    默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:

    字面上看就是这样。这个简单语句的效果如下:

    映射语句文件中的所有 select 语句将会被缓存。
    映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
    缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
    根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
    缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
    缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
    所有的这些属性都可以通过缓存元素的属性来修改。
    

    比如: <cache eviction=”FIFO” flushInterval=”60000″ size=”512″ readOnly=”true”/>
    这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。可用的收回策略有, 默认的是 LRU:

    LRU – 最近最少使用的:移除最长时间不被使用的对象。 FIFO – 先进先出:按对象进入缓存的顺序来移除它们。 SOFT –
    软引用:移除基于垃圾回收器状态和软引用规则的对象。 WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒
    形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
    size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是1024。

    readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

    相同点:Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。

    不同点:Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。

    MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。

    两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。

    而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。

    第六方面:总结

    对于总结,大家可以到各大java论坛去看一看

    相同点:Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
    Hibernate和MyBatis都支持JDBC和JTA事务处理。
    Mybatis优势
    MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
    MyBatis容易掌握,而Hibernate门槛较高。
    Hibernate优势
    Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
    Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
    Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
    Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
    他人总结
    Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
    Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。
    iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
    iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

    更多相关内容
  • 当前流行的方案有 HibernatemyBatis。两者各有优劣。竞争激烈,其中一个比较重要的考虑的地方就是性能。因此笔者通过各种实验,测出两个在相同情景下的性能相关的指数,供大家参考。 测试目标 以下测试需要...

    由于编程思想与数据库的设计模式不同,生出了一些 ORM 框架。核心都是将关系型数据库和数据转成对象型。当前流行的方案有 Hibernate 与 myBatis。两者各有优劣。竞争激烈,其中一个比较重要的考虑的地方就是性能。因此笔者通过各种实验,测出两个在相同情景下的性能相关的指数,供大家参考。

    测试目标

    以下测试需要确定几点内容:性能差异的场景;性能不在同场景下差异比;找出各架框优劣,各种情况下的表现,适用场景。

    测试思路

    测试总体分成:单表插入,关联插入,单表查询,多表查询。测试分两轮,同场景下默认参数做一轮,调优做强一轮,横纵对比分析了。测试中尽保证输入输出的一致性。样本量尽可能大,达到 10 万级别以上,减少统计误差。

    测试提纲

    具体的场景情况下插入测试 1:10 万条记录插入。查询测试 1:100 万数据中单表通过 id 查询 100000 次,无关联字段。查询测试 2:100 万数据中单表通过 id 查询 100000 次,输出关联对象字段。查询测试 3:100 万*50 万关联数据中查询 100000 次,两者输出相同字段。

    准备

    数据库:mysql 5.6 表格设计:twitter:推特

    CREATE TABLE `twitter` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `add_date` datetime DEFAULT NULL,
      `modify_date` datetime DEFAULT NULL,
      `ctx` varchar(255) NOT NULL,
      `add_user_id` bigint(20) DEFAULT NULL,
      `modify_user_id` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `UPDATE_USER_FORI` (`modify_user_id`),
      KEY `ADD_USER_FORI` (`add_user_id`),
      CONSTRAINT `ADD_USER_FORI` FOREIGN KEY (`add_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
      CONSTRAINT `UPDATE_USER_FORI` FOREIGN KEY (`modify_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=1048561 DEFAULT CHARSET=utf8
    
    
    复制代码

    user: 用户

    CREATE TABLE `user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=524281 DEFAULT CHARSET=utf8
    复制代码

    测试数据准备:

    表一:twitter

    无数据。

    表二:user

    50 万个随机的用户名。

    随机内容推特表(material_twitter)无 id,仅有随机字符串内容,共 10 万条。用于插入控推特表。

    生成数据代码,关联 100 个用户:

    insert into twitter(ctx,add_user_id,modify_user_id,add_date,modify_date)SELECT name,ROUND(RAND()*100)+1,ROUND(RAND()*100)+1,'2016-12-31','2016-12-31'from MATERIAL

    生成数据代码,关联 500000 个用户:

    insert into twitter(ctx,add_user_id,modify_user_id,add_date,modify_date)SELECT name,ROUND(RAND()*500000)+1,ROUND(RAND()*500000)+1,'2016-12-31','2016-12-31'from MATERIAL

    实体代码

    @Entity
    @Table(name = "twitter")
    public class Twitter implements java.io.Serializable{
      private Long id;
      private Date add_date;
      private Date modify_date;
      private String ctx;
      private User add_user;
      private User modify_user;
      
      private String createUserName;
      
      @Id
      @GeneratedValue(strategy = IDENTITY)
      @Column(name = "id", unique = true, nullable = false)
      public Long getId() {
        return id;
      }
      public void setId(Long id) {
        this.id = id;
      }
      @Temporal(TemporalType.DATE)
      @Column(name = "add_date")
      public Date getAddDate() {
        return add_date;
      }
      public void setAddDate(Date add_date) {
        this.add_date = add_date;
      }
      @Temporal(TemporalType.DATE)
      @Column(name = "modify_date")
      public Date getModifyDate() {
        return modify_date;
      }
      public void setModifyDate(Date modify_date) {
        this.modify_date = modify_date;
      }
      @Column(name = "ctx")
      public String getCtx() {
        return ctx;
      }
      public void setCtx(String ctx) {
        this.ctx = ctx;
      }
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "add_user_id")
      public User getAddUser() {
        return add_user;
      }
      public void setAddUser(User add_user) {
        this.add_user = add_user;
      }
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "modify_user_id")
      public User getModifyUser() {
        return modify_user;
      }
      public void setModifyUser(User modify_user) {
        this.modify_user = modify_user;
      }
      @Transient
      public String getCreateUserName() {
        return createUserName;
      }
      public void setCreateUserName(String createUserName) {
        this.createUserName = createUserName;
      }
      
    }
    
    
    复制代码

    开始

    插入测试 1

    代码操作:将随机内容推特表的数据加载到内存中,然后一条条加入到推特表中,共 10 万条。

    关键代码:hibernate:

    Session session = factory.openSession();
        session.beginTransaction();
        Twitter t = null;
        Date now = new Date();
        for(String materialTwitter : materialTwitters){
    // System.out.println("materialTwitter="+materialTwitter);
               t = new Twitter();
            t.setCtx(materialTwitter);
               t.setAddDate(now);
               t.setModifyDate(now);
               t.setAddUser(null);
               t.setModifyUser(null);
               session.save(t);
          }
        
        session.getTransaction().commit();
    
    
    复制代码

    mybatis:

    Twitter t = null;
        Date now = new Date();
        for(String materialTwitter : materialTwitters){
    // System.out.println("materialTwitter="+materialTwitter);
               t = new Twitter();
               t.setCtx(materialTwitter);
               t.setAddDate(now);
               t.setModifyDate(now);
               t.setAddUser(null);
               t.setModifyUser(null);
               msession.insert("insertTwitter", t);
          }
        msession.commit();
    复制代码

    TwitterMapper.xml,插入代码片段:

    <insert id="insertTwitter" keyProperty="id" parameterType="org.pushio.test.show1.entity.Twitter" useGeneratedKeys="true">
            insert into twitter(ctx, add_date,modify_date) values (#{ctx},#{add_date},#{modify_date})
        </insert>
    复制代码

    查询测试 1

    通过 id 从 1 递增到 10 万依次进行查询推特内容,仅输出微博内容。

    关键代码:

    hibernate:

    long cnt = 100000;
        for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)session.get(Twitter.class, i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }
    
    
    复制代码

    mybatis:

    long cnt = 100000;
        for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)msession.selectOne("getTwitter", i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }
    
    
    复制代码

    查询测试 2

    与查询测试 1 总体一样,增加微博的创建人名称字段,此处需要关联。其中微博对应有 10 万个用户。可能一部份用户重复。这里对应的用户数可能与 hibernate 配懒加载的情况有影响。

    此处体现了 hibernate 的一个方便处,可以直接通过 getAddUser()可以取得 user 相关的字段。

    然而 myBatis 则需要编写新的 vo,因此在测试 batis 时则直接在 Twitter 实体中增加创建人员名字成员(createUserName)。

    此处 hibernate 则会分别测试有懒加载,无懒加载。mybatis 会测有默认与有缓存两者情况。

    其中 mybatis 的缓存机制比较难有效配置,不适用于真实业务(可能会有脏数据),在此仅供参考。

    测试时,对推特关联的用户数做了两种情况,一种是推特共关联了 100 个用户,也就是不同的推特也就是在 100 个用户内,这里的关联关系随机生成。另外一种是推特共关联了 50 万个用户,基本上 50 个用户的信息都会被查询出来。

    在上文“准备”中可以看到关联数据生成方式。

    关键代码:

    hibernate:

    long cnt = 100000;
    for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)session.get(Twitter.class, i);
          t.getAddUser().getName();//加载相应字段
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }
    复制代码

    急懒加载配置更改处,Twitter.java:

    @ManyToOne(fetch = FetchType.EAGER)//急加载
          //@ManyToOne(fetch = FetchType.LAZY)//懒加载
      @JoinColumn(name = "add_user_id")
      public User getAddUser() {
        return add_user;
      }
    
    
    复制代码

    mybatis:

    for(long i = 1; i <= cnt; ++i){
    
    
          Twitter t = (Twitter)msession.selectOne("getTwitterHasUser", i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getCreateUserName());
        }
    复制代码

    TwitterMapper.xml 配置:

    <select id="getTwitterHasUser" parameterType="long" 
             resultType="org.pushio.test.show1.entity.Twitter">
             select twitter.*,user.name as creteUserName from twitter,user
             where twitter.id=#{id}
               AND twitter.add_user_id=user.id
    
    
         </select>
    复制代码

    测试结果

    测试分析

    测试分成了插入,单表查询,关联查询。关联查询中 hibernate 分成三种情况进行配置。其中在关联字段查询中,hibernate 在两种情况下,性能差异比较大。都是在懒加载的情况下,如果推特对应的用户比较多时,则性能会比仅映射 100 个用户的情况要差很多。

    换而言之,如果用户数量少(关联的总用户数)时,也就是会重复查询同一个用户的情况下,则不需要对用户表做太多的查询。其中通过查询文档后,证明使用懒加载时,对象会以 id 为 key 做缓存,也就是查询了 100 个用户后,后续的用户信息使用了缓存,使性能有根本性的提高。甚至要比 myBatis 更高。

    如果是关联 50 万用户的情况下,则 hibernate 需要去查询 50 万次用户信息,并组装这 50 万个用户,此时性能要比 myBatis 性能要差,不过差异不算大,小于 1ms,表示可以接受。其中 hibernate 非懒加载情况下与 myBatis 性能差异也是相对其他测试较大,平均值小于 1ms。

    这个差异的原因主要在于,myBatis 加载的字段很干净,没有太多多余的字段,直接映身入关联中。反观 hibernate 则将整个表的字都会加载到对象中,其中还包括关联的 user 字段。

    hibernate 这种情况下有好有坏,要看具体的场景,对于管理平台,需要展现的信息较多,并发要求不高时,hibernate 比较有优势。然而在一些小活动,互联网网站,高并发情况下,hibernate 的方案太不太适合,myBatis+VO 则是首选。

    测试总结

    总体初观,myBatis 在所有情况下,特别是插入与单表查询,都会微微优于 hibernate。不过差异情况并不明显,可以基本忽略差异。差异比较大的是关联查询时,hibernate 为了保证 POJO 的数据完整性,需要将关联的数据加载,需要额外地查询更多的数据。这里 hibernate 并没有提供相应的灵活性。

    关联时一个差异比较大的地方则是懒加载特性。其中 hibernate 可以特别地利用 POJO 完整性来进行缓存,可以在一级与二级缓存上保存对象,如果对单一个对象查询比较多的话,会有很明显的性能效益。以后关于单对象关联时,可以通过懒加载加二级缓存的方式来提升性能。

    最后,数据查询的性能与 orm 框架关无太大的关系,因为 orm 主要帮助开发人员将关系数据转化成对象型数据模型,对代码的深析上来看,hibernate 设计得比较重量级,对开发来说可以算是重新开发了一个数据库,不让开发去过多关心数据库的特性,直接在 hibernate 基础上进行开发,执行上分为了 sql 生成,数据封装等过程,这里花了大量的时间。

    然而 myBatis 则比直接,主要是做关联与输出字段之间的一个映射。其中 sql 基本是已经写好,直接做替换则可,不需要像 hibernate 那样去动态生成整条 sql 语句。

    好在 hibernate 在这阶段已经优化得比较好,没有比 myBatis 在性能上差异太多,但是在开发效率上,可扩展性上相对 myBatis 来说好太多。最后的最后,关于 myBatis 缓存,hibernate 查询缓等,后续会再专门做一篇测试。

    关于缓存配置

    myBatis 相对 Hibernate 等封装较为严密的 ORM 实现而言,因为 hibernate 对数据对象的操作实现了较为严密的封装,可以保证其作用范围内的缓存同步,而 ibatis 提供的是半封闭的封装实现,因此对缓存的操作难以做到完全的自动化同步。以上的缓存配置测试仅为性能上的分析,没有加入可用性上的情况,因为 myBatis 直接配置缓存的话,可能会出现脏数据。

    在关联查询数据的情况下,hiberntae 的懒加载配二级缓存是个比较好的方案(无脏数据),也是与 myBatis 相比有比较明显的优势。此情景下,性能与 myBatis 持平。

    在真实情况下,myBatis 可能不会在这个地方上配置缓存,会出现脏数据的情况,因而很有可能在此 hibernate 性能会更好。

    如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,

    ,咱们下期见!

    答案获取方式:已赞 已评 已关~

    展开全文
  • Hibernate MyBatis 哪个用?

    千次阅读 2020-07-09 15:22:20
    好在hibernate在这阶段已经优化得比较,没有比myBatis在性能上差异太多,但是在开发效率上,可扩展性上相对myBatis来说太多。最后的最后,关于myBatis缓存,hibernate查询缓等,后续会再专门做一篇测试。 关于...

    点击上方 Java后端,选择 设为星标

    优质文章,及时送达


    作者|SylvanasSun郑沐兴

    https://zhuanlan.zhihu.com/p/21966051

    前言

    由于编程思想与数据库的设计模式不同,生出了一些ORM框架。核心都是将关系型数据库和数据转成对象型。当前流行的方案有Hibernate与myBatis。两者各有优劣。竞争激烈,其中一个比较重要的考虑的地方就是性能。因此笔者通过各种实验,测出两个在相同情景下的性能相关的指数,供大家参考。

    测试目标

    以下测试需要确定几点内容:
    性能差异的场景;
    性能不在同场景下差异比;
    找出各架框优劣,各种情况下的表现,适用场景。

    测试思路

    测试总体分成:单表插入,关联插入,单表查询,多表查询。
    测试分两轮,同场景下默认参数做一轮,调优做强一轮,横纵对比分析了。
    测试中尽保证输入输出的一致性。
    样本量尽可能大,达到10万级别以上,减少统计误差。

    测试提纲

    具体的场景情况下
    插入测试1:10万条记录插入。
    查询测试1:100万数据中单表通过id查询100000次,无关联字段。
    查询测试2:100万数据中单表通过id查询100000次,输出关联对象字段。
    查询测试3:100万*50万关联数据中查询100000次,两者输出相同字段。

    准备

    数据库:mysql 5.6
    表格设计:
    twitter:推特

    CREATE TABLE `twitter` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `add_date` datetime DEFAULT NULL,
      `modify_date` datetime DEFAULT NULL,
      `ctx` varchar(255) NOT NULL,
      `add_user_id` bigint(20) DEFAULT NULL,
      `modify_user_id` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `UPDATE_USER_FORI` (`modify_user_id`),
      KEY `ADD_USER_FORI` (`add_user_id`),
      CONSTRAINT `ADD_USER_FORI` FOREIGN KEY (`add_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
      CONSTRAINT `UPDATE_USER_FORI` FOREIGN KEY (`modify_user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=1048561 DEFAULT CHARSET=utf8

    user: 用户

    CREATE TABLE `user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=524281 DEFAULT CHARSET=utf8

    测试数据准备:
    表一:twitter
    无数据。

    表二:user
    50万个随机的用户名。

    随机内容推特表(material_twitter)
    无id,仅有随机字符串内容,共10万条。
    用于插入控推特表。

    生成数据代码,关联100个用户:

    insert into twitter(ctx,add_user_id,modify_user_id,add_date,modify_date)
    SELECT name,ROUND(RAND()*100)+1,ROUND(RAND()*100)+1,'2016-12-31','2016-12-31'
    from MATERIAL

    生成数据代码,关联500000个用户:

    insert into twitter(ctx,add_user_id,modify_user_id,add_date,modify_date)
    SELECT name,ROUND(RAND()*500000)+1,ROUND(RAND()*500000)+1,'2016-12-31','2016-12-31'
    from MATERIAL

    实体代码

    @Entity
    @Table(name = "twitter")
    public class Twitter implements java.io.Serializable{
      private Long id;
      private Date add_date;
      private Date modify_date;
      private String ctx;
      private User add_user;
      private User modify_user;
      
      private String createUserName;
      
      @Id
      @GeneratedValue(strategy = IDENTITY)
      @Column(name = "id", unique = true, nullable = false)
      public Long getId() {
        return id;
      }
      public void setId(Long id) {
        this.id = id;
      }
      @Temporal(TemporalType.DATE)
      @Column(name = "add_date")
      public Date getAddDate() {
        return add_date;
      }
      public void setAddDate(Date add_date) {
        this.add_date = add_date;
      }
      @Temporal(TemporalType.DATE)
      @Column(name = "modify_date")
      public Date getModifyDate() {
        return modify_date;
      }
      public void setModifyDate(Date modify_date) {
        this.modify_date = modify_date;
      }
      @Column(name = "ctx")
      public String getCtx() {
        return ctx;
      }
      public void setCtx(String ctx) {
        this.ctx = ctx;
      }
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "add_user_id")
      public User getAddUser() {
        return add_user;
      }
      public void setAddUser(User add_user) {
        this.add_user = add_user;
      }
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "modify_user_id")
      public User getModifyUser() {
        return modify_user;
      }
      public void setModifyUser(User modify_user) {
        this.modify_user = modify_user;
      }
      @Transient
      public String getCreateUserName() {
        return createUserName;
      }
      public void setCreateUserName(String createUserName) {
        this.createUserName = createUserName;
      }
      
    }

    开始

    插入测试1
    代码操作:
    将随机内容推特表的数据加载到内存中,然后一条条加入到推特表中,共10万条。


    关键代码:
    hibernate:

    Session session = factory.openSession();
        session.beginTransaction();
        Twitter t = null;
        Date now = new Date();
        for(String materialTwitter : materialTwitters){
    // System.out.println("materialTwitter="+materialTwitter);
               t = new Twitter();
            t.setCtx(materialTwitter);
               t.setAddDate(now);
               t.setModifyDate(now);
               t.setAddUser(null);
               t.setModifyUser(null);
               session.save(t);
          }
        
        session.getTransaction().commit();
    
    mybatis:
    
      
        Twitter t = null;
        Date now = new Date();
        for(String materialTwitter : materialTwitters){
    // System.out.println("materialTwitter="+materialTwitter);
               t = new Twitter();
               t.setCtx(materialTwitter);
               t.setAddDate(now);
               t.setModifyDate(now);
               t.setAddUser(null);
               t.setModifyUser(null);
               msession.insert("insertTwitter", t);
          }
        msession.commit();

    TwitterMapper.xml,插入代码片段:

    <insert id="insertTwitter" keyProperty="id" parameterType="org.pushio.test.show1.entity.Twitter" useGeneratedKeys="true">
         insert into twitter(ctx, add_date,modify_date) values (#{ctx},#{add_date},#{modify_date})
    </insert>

    查询测试1

    通过id从1递增到10万依次进行查询推特内容,仅输出微博内容。
    关键代码:
    hibernate:

    long cnt = 100000;
        for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)session.get(Twitter.class, i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }

    mybatis:

    long cnt = 100000;
        for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)msession.selectOne("getTwitter", i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }

    查询测试2

    与查询测试1总体一样,增加微博的创建人名称字段,此处需要关联。
    其中微博对应有10万个用户。可能一部份用户重复。这里对应的用户数可能与hibernate配懒加载的情况有影响。

    此处体现了hibernate的一个方便处,可以直接通过getAddUser()可以取得user相关的字段。

    然而myBatis则需要编写新的vo,因此在测试batis时则直接在Twitter实体中增加创建人员名字成员(createUserName)。

    此处hibernate则会分别测试有懒加载,无懒加载。
    mybatis会测有默认与有缓存两者情况。

    其中mybatis的缓存机制比较难有效配置,不适用于真实业务(可能会有脏数据),在此仅供参考。

    测试时,对推特关联的用户数做了两种情况,一种是推特共关联了100个用户,也就是不同的推特也就是在100个用户内,这里的关联关系随机生成。
    另外一种是推特共关联了50万个用户,基本上50个用户的信息都会被查询出来。

    在上文“准备”中可以看到关联数据生成方式。

    关键代码:
    hibernate:

    long cnt = 100000;
    for(long i = 1; i <= cnt; ++i){
          Twitter t = (Twitter)session.get(Twitter.class, i);
          t.getAddUser().getName();//加载相应字段
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getAddUser().getName());
        }

    急懒加载配置更改处,Twitter.java:

    @ManyToOne(fetch = FetchType.EAGER)//急加载
          //@ManyToOne(fetch = FetchType.LAZY)//懒加载
      @JoinColumn(name = "add_user_id")
      public User getAddUser() {
        return add_user;
      }

    mybatis:

    for(long i = 1; i <= cnt; ++i){
    
          Twitter t = (Twitter)msession.selectOne("getTwitterHasUser", i);
          //System.out.println("t.getCtx="+ t.getCtx() + " t.getUser.getName=" + t.getCreateUserName());
        }

    TwitterMapper.xml配置:

    <select id="getTwitterHasUser" parameterType="long"
             resultType="org.pushio.test.show1.entity.Twitter">
             select twitter.*,user.name as creteUserName from twitter,user
             where twitter.id=#{id}
               AND twitter.add_user_id=user.id
    </select>

    测试结果

    测试分析

    测试分成了插入,单表查询,关联查询。关联查询中hibernate分成三种情况进行配置。其中在关联字段查询中,hibernate在两种情况下,性能差异比较大。都是在懒加载的情况下,如果推特对应的用户比较多时,则性能会比仅映射100个用户的情况要差很多。

    换而言之,如果用户数量少(关联的总用户数)时,也就是会重复查询同一个用户的情况下,则不需要对用户表做太多的查询。其中通过查询文档后,证明使用懒加载时,对象会以id为key做缓存,也就是查询了100个用户后,后续的用户信息使用了缓存,使性能有根本性的提高。甚至要比myBatis更高。

    如果是关联50万用户的情况下,则hibernate需要去查询50万次用户信息,并组装这50万个用户,此时性能要比myBatis性能要差,不过差异不算大,小于1ms,表示可以接受。其中hibernate非懒加载情况下与myBatis性能差异也是相对其他测试较大,平均值小于1ms。

    这个差异的原因主要在于,myBatis加载的字段很干净,没有太多多余的字段,直接映身入关联中。反观hibernate则将整个表的字都会加载到对象中,其中还包括关联的user字段。

    hibernate这种情况下有好有坏,要看具体的场景,对于管理平台,需要展现的信息较多,并发要求不高时,hibernate比较有优势。
    然而在一些小活动,互联网网站,高并发情况下,hibernate的方案太不太适合,myBatis+VO则是首选。

    测试总结

    总体初观,myBatis在所有情况下,特别是插入与单表查询,都会微微优于hibernate。不过差异情况并不明显,可以基本忽略差异。差异比较大的是关联查询时,hibernate为了保证POJO的数据完整性,需要将关联的数据加载,需要额外地查询更多的数据。这里hibernate并没有提供相应的灵活性。

    关联时一个差异比较大的地方则是懒加载特性。其中hibernate可以特别地利用POJO完整性来进行缓存,可以在一级与二级缓存上保存对象,如果对单一个对象查询比较多的话,会有很明显的性能效益。以后关于单对象关联时,可以通过懒加载加二级缓存的方式来提升性能。

    最后,数据查询的性能与orm框架关无太大的关系,因为orm主要帮助开发人员将关系数据转化成对象型数据模型,对代码的深析上来看,hibernate设计得比较重量级,对开发来说可以算是重新开发了一个数据库,不让开发去过多关心数据库的特性,直接在hibernate基础上进行开发,执行上分为了sql生成,数据封装等过程,这里花了大量的时间。

    然而myBatis则比直接,主要是做关联与输出字段之间的一个映射。其中sql基本是已经写好,直接做替换则可,不需要像hibernate那样去动态生成整条sql语句。


    好在hibernate在这阶段已经优化得比较好,没有比myBatis在性能上差异太多,但是在开发效率上,可扩展性上相对myBatis来说好太多。最后的最后,关于myBatis缓存,hibernate查询缓等,后续会再专门做一篇测试。

    关于缓存配置

    myBatis相对Hibernate 等封装较为严密的ORM 实现而言,因为hibernate对数据对象的操作实现了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭的封装实现,因此对缓存的操作难以做到完全的自动化同步。以上的缓存配置测试仅为性能上的分析,没有加入可用性上的情况,因为myBatis直接配置缓存的话,可能会出现脏数据。

    在关联查询数据的情况下,hiberntae的懒加载配二级缓存是个比较好的方案(无脏数据),也是与myBatis相比有比较明显的优势。此情景下,性能与myBatis持平。


    在真实情况下,myBatis可能不会在这个地方上配置缓存,会出现脏数据的情况,因而很有可能在此hibernate性能会更好。

    展开全文
  • 首先从orm(object relation mapping)等级来讲,hibernate和mybatis都属于orm框架,hibernate属于4级(顶级),mybatis属于2级。从此可见,hibernatemybatis更强大一些,强大的体现在于: ●开发速度与工作量。 ...

    首要声明,该篇文章的编写是依据其他多篇文章汇总整理而来。并非完全原创,只为加深自己的理解的同时方便大家,侵权必删!


    首先从orm(object relation mapping)等级来讲,hibernate和mybatis都属于orm框架,hibernate属于4级(顶级),mybatis属于2级。从此可见,hibernate比mybatis更强大一些,强大的体现在于:

    开发速度与工作量。

    hibernate简化了dao层,使用者不需要考虑sql语句的编写与执行以及结果映射,将着重点放在业务逻辑上,而mybatis需要使用者手写sql语句以及resultMap,所以hibernate开发速度要比mybatis快。但是hibernate门槛要比mybatis高,两者之间做选择时要根据项目实际需求作为标准,如:项目绝大多数是简单的数据操作,比如增删改查,没有太多的复杂sql语句,这时选择hibernate用于dao工具会更简便、效率更高一些;反之,如果项目有很多复杂的sql语句,则适合选择mybatis,因为mybatis可以进行更为细致的sql优化,可以减少查询字段从而提高效率(因为hibernate会把所有字段都进行处理,效率会稍低)。

    当然hibernate也可以通过使用者自行编写sql语句与数据库交互,比如HQL查询、原生SQL查询,但是这样我个人认为就违背了hibernate简化dao层的初衷。

    ●缓存方面(简单了解下,欲深究可以看看其它文章,本文章后续再做补充)

    hibernate的一级缓存是session缓存,这个涉及到session生命周期和hibernate对象状态(瞬时状态,亦称临时状态、持久化状态、离线状态,亦称游离状态、托管状态),个人理解,hibernate的一级缓存和快照机制可以很好地减轻数据库任务,因为当缓存中对象与快照相比较无变化时不回去操作数据库。二级缓存暂时不说。

    mybatis缓存机制可以使用者自己配置和定制,比较方便。

    例:

    两者比较:因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。

    该图片截取自:https://www.cnblogs.com/inspurhaitian/p/4647485.html

    展开全文
  • 通过本文给分享了hibernate和mybatis对比分析,从开发对比,系统调优对比,对象管理与抓取策略,缓存机制对比等方面给大家详细介绍,需要的朋友参考下吧
  • Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。 针对高级查询,Mybatis需要手动编写SQL语句,以及R Java开源项目【ali1024.coding.net/public/P7/Java/git】 esultMap。而Hibernate
  • spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码。代码拿过去即可集成使用。
  • hibernate和mybatis的区别

    2021-06-08 17:40:43
     针对简单逻辑,HibernateMyBatis都有相应的代码生成工具,可以生成简单基本的DAO层方法。  针对高级查询,MyBatis需要手动编写SQL语句,以及ResultMap,而Hibernate有良好的映射机制,开发者无需关心SQL的生成...
  • Hibernate和Mybatis

    2018-09-15 22:28:46
    MybatisHibernate都是Java持久层框架,在业务逻辑层进行数据库持久化
  • 2.Hibernate和mybatis的区别(常见) Hibernate是一个完整的ORM框架,功能更加强大,操作更加简单(性能不好控制),如果你要使用Hibernate控制性能,你必须是一个Hinernate高手。 对于一个大项目,Hibernate确实不是...
  • Hibernate和Mybatis对比

    2020-07-05 18:32:01
    一、Hibernate和Mybatis是什么? hibernate: hibernate的特点 (1)对象化。Hibernate可以让开发人员以面相对象的思想来操作数据库。 (2)更的移植性。对于不同的数据库,开发者只需要使用相同的数据操作即可,...
  • 1、Hibernate和Mybatis都属于ORM框架, 2、映射声明区别 Hibernate的映射关系是通过xml文件声明; Mybatis是通过typeHandlers(类型转换器)来完成的;(类字段表字段的转换),隐式转换,如果转换不成功则需要...
  • 主要介绍了HibernateMybatis 如何共存?本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • HibernateMyBatis详解

    2018-08-08 11:18:18
    Hibernate&amp;amp;nbsp;是当前最流行的O/R mapping框架,它出身于sf.net,现在已经成为Jboss的一部分。&amp;amp;nbsp;Mybatis&amp;amp;nbsp;是另外一种优秀的O/R mapping框架。目前属于apache的一个子...
  • JPA、HibernateMybatis简单了解 JPA:本身是一种ORM规范,不是ORM框架....3.MyBatis:本是apache的一个开源项目iBatis,提供的持久层框架包括SQL MapsDao,允许开发人员直接编写SQL(更灵活).(Sql操作方.
  • springboot(4) 整合mybatis和hibernate 请删除项目中本地仓库的配置,或者改成国内的公共仓库,否则将无法启动
  • 持久化:持久化(Persistence)是程序数据在瞬时状态(如内存中的对象)持久状态(可永久保存的存储设备中,如磁盘)间转换的过程。持久化的主要应用是将内存中的数据存储在关系型的数据库中,也可以存储在磁盘文件...
  • hibernatemybatis一起使用取长补短

    热门讨论 2011-10-21 14:00:03
    一个项目中同时使用hibernate和ibatis两个orm框架,既利用到了hibernate的强大功能也弥补到了hibernate对大数据操作的性能上的影响
  • hibernatemybatis

    2022-01-14 11:29:49
    hibernate和mybatis 使用场景: hibernate适用于一些需求变化不多的项目,比如:某某后台管理系统,学生管理系统,OA等。 mybatis使用与一些需求变化比较多的项目,比如:电商平台等互联网项目 共同点:都是一个持久...
  • 1.Hibernate 在管理系统时代,首先是实现业务逻辑,然后才是性能,所以Hibernate在当时是主流。 2.MyBatis 在移动互联网时代,MyBatis是首选,不屏蔽SQL,程序员可以自己制定SQL规则,能更加精确定义SQL,从而...
  • Hibernate和MyBatis区别

    万次阅读 2018-11-30 19:31:09
    应用性: Hibernate应用相对广泛、映射封装比较深、比较丰富。 从文档的丰富性,产品的完善性,版本的开发速度都要强于ibatis.。 ...MyBatis非常简单易学,Hibernate相对较复杂,门槛较高。  ...
  • hibernate和mybatis区别.txtMybatis优势 MyBatis可以进行更为细致的SQL优化,可以减少查询字段。 MyBatis容易掌握,而Hibernate门槛较高。 Hibernate优势 Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL...
  • 1)sql 优化方面 Hibernate 不需要编写大量的 SQL,就可以完全映射,提供了日志、缓存、级联(级联比 MyBatis ...MyBatis 是一个半自动映射的框架,因为 MyBatis 需要手动匹配 POJO、SQL 映射关系。 Hibernate 是一
  • hibernate和mybatis异同

    2018-07-04 00:52:17
    这几天去面试,看到现在很多公司还在使用hibernate,于是由感地回来复习了一下hibernatehibernate 是一个orm对象关系映射的持久...hibernatemybatis有更的二级缓存机制,也可以使用第三方缓存数据库。hibernate...
  • NULL 博文链接:https://darrenzhu.iteye.com/blog/2044117
  • Hibernate和MyBatis的区别

    万次阅读 多人点赞 2018-12-31 23:32:21
    摘抄自:《javaEE互联网轻量级框架整合开发》 ...无论MyBatisHibernate都可以称为ORM框架,Hibernate的设计理念是完全面向POJO的,而MyBatis不是。 Hibernate基本不再需要编写SQL就可以通过映射关系来操作...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,634
精华内容 27,053
关键字:

hibernate和mybatis哪个好