问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

实战测试告诉你MyBatis与Hibernate到底哪个性能更好

发布网友 发布时间:2024-09-17 06:52

我来回答

1个回答

热心网友 时间:2024-09-20 23:37

前言

由于编程思想与数据库的设计模式不同,生出了一些ORM框架。

核心都是将关系型数据库和数据转成对象型。当前流行的方案有Hibernate与myBatis。

两者各有优劣。竞争激烈,其中一个比较重要的考虑的地方就是性能。

因此笔者通过各种实验,测出两个在相同情景下的性能相关的指数,供大家参考。

友情提示:如果你嫌弃文章太长,可以拉到文末看结论即可。

测试目标

以下测试需要确定几点内容:

性能差异的场景;

性能不在同场景下差异比;

找出各架框优劣,各种情况下的表现,适用场景。

测试思路

测试总体分成:单表插入,关联插入,单表查询,多表查询。

测试分两轮,同场景下默认参数做一轮,调优做强一轮,横纵对比分析了。

测试中尽保证输入输出的一致性。

样本量尽可能大,达到10万级别以上,减少统计误差。

测试提纲

具体的场景情况下

插入测试1:10万条记录插入。

查询测试1:100万数据中单表通过id查询100000次,无关联字段。

查询测试2:100万数据中单表通过id查询100000次,输出关联对象字段。

查询测试3:100万*50万关联数据中查询100000次,两者输出相同字段。

准备

数据库:mysql5.6

表格设计:

*:*

CREATETABLE`*`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`add_date`datetimeDEFAULTNULL,`modify_date`datetimeDEFAULTNULL,`ctx`varchar(255)NOTNULL,`add_user_id`bigint(20)DEFAULTNULL,`modify_user_id`bigint(20)DEFAULTNULL,PRIMARYKEY(`id`),KEY`UPDATE_USER_FORI`(`modify_user_id`),KEY`ADD_USER_FORI`(`add_user_id`),CONSTRAINT`ADD_USER_FORI`FOREIGNKEY(`add_user_id`)REFERENCES`user`(`id`)ONDELETESETNULL,CONSTRAINT`UPDATE_USER_FORI`FOREIGNKEY(`modify_user_id`)REFERENCES`user`(`id`)ONDELETESETNULL)ENGINE=InnoDBAUTO_INCREMENT=1048561DEFAULTCHARSET=utf8

user:用户

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=524281DEFAULTCHARSET=utf8

测试数据准备:

表一:*

无数据。

表二:user

50万个随机的用户名。

随机内容*表(material_*)

无id,仅有随机字符串内容,共10万条。

用于插入控*表。

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

insertinto*(ctx,add_user_id,modify_user_id,add_date,modify_date)SELECTname,ROUND(RAND()*100)+1,ROUND(RAND()*100)+1,'2016-12-31','2016-12-31'fromMATERIAL

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

insertinto*(ctx,add_user_id,modify_user_id,add_date,modify_date)SELECTname,ROUND(RAND()*500000)+1,ROUND(RAND()*500000)+1,'2016-12-31','2016-12-31'fromMATERIAL

实体代码

@Entity@Table(name="*")publicclassTwitterimplementsjava.io.Serializable{privateLongid;privateDateadd_date;privateDatemodify_date;privateStringctx;privateUseradd_user;privateUsermodify_user;privateStringcreateUserName;@Id@GeneratedValue(strategy=IDENTITY)@Column(name="id",unique=true,nullable=false)publicLonggetId(){returnid;}publicvoidsetId(Longid){this.id=id;}@Temporal(TemporalType.DATE)@Column(name="add_date")publicDategetAddDate(){returnadd_date;}publicvoidsetAddDate(Dateadd_date){this.add_date=add_date;}@Temporal(TemporalType.DATE)@Column(name="modify_date")publicDategetModifyDate(){returnmodify_date;}publicvoidsetModifyDate(Datemodify_date){this.modify_date=modify_date;}@Column(name="ctx")publicStringgetCtx(){returnctx;}publicvoidsetCtx(Stringctx){this.ctx=ctx;}@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="add_user_id")publicUsergetAddUser(){returnadd_user;}publicvoidsetAddUser(Useradd_user){this.add_user=add_user;}@ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="modify_user_id")publicUsergetModifyUser(){returnmodify_user;}publicvoidsetModifyUser(Usermodify_user){this.modify_user=modify_user;}@TransientpublicStringgetCreateUserName(){returncreateUserName;}publicvoidsetCreateUserName(StringcreateUserName){this.createUserName=createUserName;}}开始

插入测试1

代码操作:

将随机内容*表的数据加载到内存中,然后一条条加入到*表中,共10万条。

关键代码:

hibernate:

Sessionsession=factory.openSession();session.beginTransaction();Twittert=null;Datenow=newDate();for(StringmaterialTwitter:materialTwitters){//System.out.println("materialTwitter="+materialTwitter);t=newTwitter();t.setCtx(materialTwitter);t.setAddDate(now);t.setModifyDate(now);t.setAddUser(null);t.setModifyUser(null);session.save(t);}session.getTransaction().commit();

mybatis:

Twittert=null;Datenow=newDate();for(StringmaterialTwitter:materialTwitters){//System.out.println("materialTwitter="+materialTwitter);t=newTwitter();t.setCtx(materialTwitter);t.setAddDate(now);t.setModifyDate(now);t.setAddUser(null);t.setModifyUser(null);msession.insert("insertTwitter",t);}msession.commit();

TwitterMapper.xml,插入代码片段:

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

查询测试1

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

关键代码:

hibernate:

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

mybatis:

longcnt=100000;for(longi=1;i<=cnt;++i){Twittert=(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:

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=524281DEFAULTCHARSET=utf80

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

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=524281DEFAULTCHARSET=utf81

mybatis:

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=524281DEFAULTCHARSET=utf82

TwitterMapper.xml配置:

CREATETABLE`user`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=524281DEFAULTCHARSET=utf83

测试结果

测试分析

测试分成了插入,单表查询,关联查询。关联查询中hibernate分成三种情况进行配置。

其中在关联字段查询中,hibernate在两种情况下,性能差异比较大。都是在懒加载的情况下,如果*对应的用户比较多时,则性能会比仅映射100个用户的情况要差很多。

换而言之,如果用户数量少(关联的总用户数)时,也就是会重复查询同一个用户的情况下,则不需要对用户表做太多的查询。

其中通过查询文档后,证明使用懒加载时,对象会以id为key做缓存,也就是查询了100个用户后,后续的用户信息使用了缓存,使性能有根本性的提高。甚至要比myBatis更高。

如果是关联50万用户的情况下,则hibernate需要去查询50万次用户信息,并组装这50万个用户,此时性能要比myBatis性能要差,不过差异不算大,小于1ms,表示可以接受。

其中hibernate非懒加载情况下与myBatis性能差异也是相对其他测试较大,平均值小于1ms。

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

hibernate这种情况下有好有坏,要看具体的场景,对于管理平台,需要展现的信息较多,并发要求不高时,hibernate比较有优势。

然而在一些小活动,互联网网站,高并发情况下,hibernate的方案太不太适合,myBatis+VO则是首选。

另外,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的MyBatis系列面试题和答案,非常齐全。

测试总结

总体初观,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性能会更好。

作者:郑沐兴

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
高启强与陈书婷结婚是哪一集 陈舒婷和高启强第几集结婚 高启强陈书婷结婚是第几集 高启强和陈书婷结婚是第几集 高启强和陈书婷第几集结的婚 狂飙高启强第几集和大嫂在一起的 2021年清明节时间(是公历几月几号) js中类似`${xx,xxxy}`的语句是什么意思? 用支付宝帐号注册的淘宝帐号但是淘宝显示未绑定支付宝帐号如图 银行黑户影响子女什么 为什么就是查询不了中文,数字和英文都没有问题,感谢解答。急用。都有... 汽车买全保大概多少钱 汽车全保包括哪些 吃了十全大补丸做了房事有影响吗? 车辆全保包括哪些 十全大补丸早上吃了晚上喝酒了没吃有什么危害 车的全保包括哪些 天天吃花生会胖吗 “积草摊渔网”的出处是哪里 南齐书顾欢传原文及翻译 拼多多如何找回支付密码? 拼多多怎么找回原来的账号密码 怎么找回拼多多的登录密码? 什么是免疫疗法?肿瘤免疫疗法的优势是什么? 依维卡靶向疗法和免疫疗法好吗? 胃癌免疫治疗和靶向治疗哪个好 免疫治疗和靶向治疗有什么区别 哪些好春联 好的春联有哪些 河北师范大学法学硕士学位研究生中哪个专业是最强的。是本校最好的专... 什么是CNAS认可和CMA? ...直接在mysql中可以运行,但用hibernate查不能识别":=" 路在脚下!教你怎样将Java接到MySQL数据库,涨薪不在话下! java学完基础直接学框架(学java框架要多久) 电视剧《一路格桑花中》安静的手机铃声叫什么? 现在中央电视台播放的&lt;一路格桑花&gt;中那个安静的手机铃声是什么歌曲啊... 中央一套电视剧《一路格桑花》中安静的妹的手机铃声是什么 中央一台正在播出的电视剧《一路格桑花》中安静的手机铃声是那首歌? 一路格桑花里边安静的手机铃声是什么音乐啊? 重庆居民离婚后户口怎么处理可以迁到爸妈那里去吗 重庆离婚需要什么证件 滴滴打车如何改支付宝 一台电脑主机如何连接三个显示屏显示? 一台主机如何连接三个显示屏显示 一台主机如何连接三个显示屏显示? 主机和显示器怎么连接主机和显示器怎么连接的呢 万智牌关于衍生物消失的两个疑问,求高玩大大。 万智牌 不会毁坏是什么意思? 万智牌是不是所有的天使自带辟邪属性? 万智牌什么牌克制不灭 万智牌 当一个生 物受到致死伤害时 就直接进入坟场吗?有没有手段可_百...