date比较大小 mybatis_Hibernate 和 MyBatis 哪个更好用?

87d6d5d27e3b98119386ae9e11ced0e3.png  Java大联盟

  帮助万千Java学习者持续成长

关注

da047d81878c2c78f8af80f65d20f43c.gif

作者|SylvanasSun郑沐兴

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

B 站搜索:楠哥教你学Java

获取更多优质视频教程

前言

由于编程思想与数据库的设计模式不同,生出了一些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.idselect>

测试结果

6807be9af569986e5de897c251d24b74.png

测试分析

测试分成了插入,单表查询,关联查询。关联查询中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性能会更好。

推荐阅读

1、Spring Boot+Vue项目实战

2、B站:4小时上手MyBatis Plus

3、一文搞懂前后端分离

4、快速上手Spring Boot+Vue前后端分离

楠哥简介

资深 Java 工程师,微信号 southwindss

《Java零基础实战》一书作者,今日头条认证大V

GitChat认证作者,B站认证UP主(楠哥教你学Java)

致力于帮助万千 Java 学习者持续成长。

23b7a0d09cd56d650cd2b5da38596be7.png

有收获,就在看5f5336f5b0c29a23ef57f68911865955.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单的cpu飙升排查方法

1先来一段飙升代码 public class FindJavaThreadInTaskManager {public static void main(String[] args) {Thread thread new Thread(new Worker());thread.start();}static class Worker implements Runnable {Overridepublic void run() {while (true) {System.out.printl…

tortoisesvn创建部署项目_FrameWork如何进行云托管部署

介绍CloudBase Framework 是云开发官方出品的云原生一体化部署工具&#xff0c;可以帮助开发者将静态网站、后端服务和小程序等应用&#xff0c;一键部署到云开发 Serverless 架构的云平台上&#xff0c;自动伸缩且无需关心运维&#xff0c;聚焦应用本身&#xff0c;无需关心底…

修改背景图片_我花了5小时,为网易修改了一份内容超多的PPT,效果超级赞!!...

微信扫码观看全套Excel、Word、PPT视频作者&#xff1a;宋雪贤 来源&#xff1a;PPT进化论(ID&#xff1a;PPTjinhualun)哈喽&#xff0c;大家好&#xff0c;不知道您看过《我花了3个小时&#xff0c;为京东修改了一份PPT&#xff0c;效果好到惊人&#xff01;》这篇案例修改文…

MySQL千万级别大表如何优化?

当MySQL单表记录数过大时&#xff0c;增删改查性能都会急剧下降&#xff0c;可以参考以下步骤来优化&#xff1a; 单表优化 除非单表数据未来会一直不断上涨&#xff0c;否则不要一开始就考虑拆分&#xff0c;拆分会带来逻辑、部署、运维的各种复杂度&#xff0c;一般以整型值…

命令测试post_【第2088期】前端中台化,把格局做大——NodeJS 和测试服务探索

前言今日早读文章由《React状态管理与同构实战》作者LucasHC投稿分享。正文从这开始~~近些年&#xff0c;「NodeJS 应该如何在公司业务中真实落地 」这类问题屡见不鲜。自从 2009 年 NodeJS 诞生之后&#xff0c;抢尽风头&#xff0c;圈粉无数。但一定有工程师不禁要质疑「Node…

Java 诊断工具 Arthas 常见命令

基本概念 云原生这么多微服务&#xff0c;当然需要一个诊断利器来排查问题。 Arthas 是阿里开源的 Java 诊断工具&#xff0c;深受开发者喜爱。在线排查问题&#xff0c;无需重启&#xff1b;动态跟踪 Java 代码&#xff1b;实时监控 JVM 状态。Arthas 支持 JDK 6&#xff0c…

28和lba48命令格式区别_编译Sass(命令行)

本文作者&#xff1a;开课吧无忧图文编辑&#xff1a;开三金sass编译有很多种方式&#xff0c;如命令行编译模式、编辑器自动编译、编译软件koala、sass-loader等。今天我们就先来看第一种&#xff1a;命令行编译刚才我在test文件夹里面已经建立了一个style.scss文件&#xff0…

子窗体中组合框联动_一张表实现组合框联动

嗨&#xff0c;大家中午好&#xff01;最近&#xff0c;有网友给我私信&#xff0c;想要一个联动的示例&#xff0c;一个有关于部门联动的操作。其实关于联动的操作有很多&#xff0c;可以是组合框的联动&#xff0c;列表框联动&#xff0c;组合框与列表框也可以联动&#xff0…

中如何实现文字转语音_录音转文字、文字转语音,学会这一招就够了!手把手教你如何操作...

阅读文章时候想着有人可以把文章读给我听就好了&#xff0c;写作时想着语音直接可以转换成文字就好了&#xff0c;大家是不是有时会突然冒出这样的想法&#xff1f;七十这些看似天真的想法&#xff0c;还真的有办法解决&#xff0c;这里就手把手教你如何操作才能将的文字转换成…

图像 理想低通滤波_图像处理之滤波(下)

[toc]目录一、常规滤波低通高通带通带阻二、非局部均值滤波三、维纳滤波四、卡尔曼滤波前言所谓滤波&#xff0c;其实就是从混合在一起的诸多信号中提取出所需要的信号。信号的分类&#xff1a;确定型信号&#xff0c;可以表示为确定的时间函数&#xff0c;可确定其在任何时刻的…

泰山行宫碧霞元君祠_临清市泰山行宫碧霞元君祠5月4号(农历三月三十日)举行大型泰山奶奶接驾法会...

临清是泰山奶奶的娘家&#xff0c;每年的四月泰山奶奶要回临清省亲临清市道教协会定于2019年农历三月三十(5月4号星期六)于临清桑树园泰山行宫碧霞元君祠举行大型泰山奶奶迎鸾接驾庙会。届时&#xff0c;将有架鼓会、云龙会、狮胞会、钢叉会、高跷会、天音会、彩船会、秧歌会等…

充分条件反过来是必要条件吗_“充分必要条件”引发的现实思考

昨天看了一篇文章是介绍“充分条件和必要条件”&#xff0c;大致就是A能直接推导出B&#xff0c;那A就是B的充分条件。A不一定能推导出B&#xff0c;但是没A一定推导不出B&#xff0c;那A就是B必要条件。举个简单的例子&#xff1a;对你好&#xff08;A&#xff09;与喜欢你&am…

手机游戏降低游戏延迟的软件_怎么降低手机网络延迟(减少网络延迟的5个小技巧)...

在过去的几十年里&#xff0c;用户或开发人员并不担心延迟。在上世纪90年代和本世纪初&#xff0c;个人互联网连接速度要慢得多&#xff0c;因此发送请求和接收响应之间的延迟要远远小于下载完成所需的时间。如今&#xff0c;更高的带宽连接使下载速度更快&#xff0c;因此延迟…

mysql极客_极客mysql16

1.MySQL会为每个线程分配一个内存(sort_buffer)用于排序该内存大小为sort_buffer_size1>如果排序的数据量小于sort_buffer_size&#xff0c;排序将会在内存中完成2>如果排序数据量很大&#xff0c;内存中无法存下这么多数据&#xff0c;则会使用磁盘临时文件来辅助排序&a…

linux 测试环境启用jar_Linux下搭建测试环境

一、下载安装包https://pan.baidu.com/s/1h-Nk8HcWKKtqbjrn0J_t1g 457jJDK1.8安装包、Tomcat8安装包本文用的远程连接Linux操作系统的客户端工具为Xshell&#xff0c;相关使用请自行百度二、安装JDK1、先检查该环境是否已经安装过jdk。输入java -version。如果有&#xff0c;…

代码中 密码存储_你还记得浏览器自动存储的密码吗?用js代码恢复一下记忆吧...

哈喽大家好我是无知便是罪专注于收集和分享互联网上不为人知的好东西正常来说我们的手机和浏览器都有一个非常实用的功能就是可以自动的加密存储我们的常用密码了然后呢在我们需要的时候呢它可以自动填入进来非常非常的省时省力不过呢这种功能的我们用久了就很容易忘记自己当初…

diff算法阮一峰_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法

前言文章的一开头&#xff0c;还是要强调下字符串匹配的思路将模式串和主串进行比较从前往后比较从后往前比较2. 匹配时&#xff0c;比较主串和模式串的下一个位置3. 失配时,在模式串中寻找一个合适的位置如果找到&#xff0c;从这个位置开始与主串当前失配位置进行比较如果未找…

python input 拖入路径 去除转义 空格_python学习笔记(基础-2)(转载)

1.输出用print()在括号中加上字符串&#xff0c;就可以向屏幕上输出指定的文字。2.输入如果要让用户从电脑输入一些字符怎么办&#xff1f;Python提供了一个input()&#xff0c;可以让用户输入字符串&#xff0c;并存放到一个变量里。输入是Input&#xff0c;输出是Output&…

mysql和mdy_Liunx下安装MySql

1.安装数据库&#xff1a;执行命令 yum -y install mysql-server2.启动数据库&#xff1a;安装完毕&#xff0c;执行命令service mysqld start3.登录数据库&#xff1a;mysql -u root -p回车后输入密码(mysql的默认用户名是root&#xff0c;密码为空)4.使用数据库&#xff1a;登…

python websocket服务器https_Socket与WebSocket以及http与https重新总结

Socket与WebSocket以及http与https重新总结一.Socket网络中的Socket是一个抽象的接口 &#xff0c;而是为了方便使用TCP或UDP而抽象出来的一层 &#xff0c;可以理解为网络中连接的两端。通常被叫做套接字接口.二.WebSocketWebSocket就是其中一种&#xff0c;是为了创建一种双向…