【109期】面试官问:说说 MyBatis 和 Hibernate JPA,哪个性能更佳?

最后总结

搞定算法,面试字节再不怕,有需要文章中分享的这些二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析

最后再分享一份终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化

image

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

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 into twitter(ctx, add_date,modify_date) values (#{ctx},#{add_date},#{modify_date})

查询测试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面试题,公众号Java精选,回复Java面试,获取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 twitter.*,user.name as creteUserName from twitter,user

where twitter.id=#{id}

AND twitter.add_user_id=user.id

测试结果

测试分析

测试分成了插入,单表查询,关联查询。关联查询中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查询缓等,后续会再专门做一篇测试。

总结

上述知识点,囊括了目前互联网企业的主流应用技术以及能让你成为“香饽饽”的高级架构知识,每个笔记里面几乎都带有实战内容。

很多人担心学了容易忘,这里教你一个方法,那就是重复学习。

打个比方,假如你正在学习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。

从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

几乎都带有实战内容。

很多人担心学了容易忘,这里教你一个方法,那就是重复学习。

打个比方,假如你正在学习 spring 注解,突然发现了一个注解@Aspect,不知道干什么用的,你可能会去查看源码或者通过博客学习,花了半小时终于弄懂了,下次又看到@Aspect 了,你有点郁闷了,上次好像在哪哪哪学习,你快速打开网页花了五分钟又学会了。

从半小时和五分钟的对比中可以发现多学一次就离真正掌握知识又近了一步。

[外链图片转存中…(img-Et94vdPL-1715476172504)]

人的本性就是容易遗忘,只有不断加深印象、重复学习才能真正掌握,所以很多书我都是推荐大家多看几遍。哪有那么多天才,他只是比你多看了几遍书。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值