西安到北京的高铁时刻表查询,企业网站seo优,wordpress简洁自适应主题,做网站银川Java大联盟帮助万千Java学习者持续成长关注作者#xff5c;SylvanasSun郑沐兴https://zhuanlan.zhihu.com/p/21966051B 站搜索#xff1a;楠哥教你学Java获取更多优质视频教程前言由于编程思想与数据库的设计模式不同#xff0c;生出了一些ORM框架。核心都是将关系型数据库和… Java大联盟 帮助万千Java学习者持续成长关注作者SylvanasSun郑沐兴https://zhuanlan.zhihu.com/p/21966051B 站搜索楠哥教你学Java获取更多优质视频教程前言由于编程思想与数据库的设计模式不同生出了一些ORM框架。核心都是将关系型数据库和数据转成对象型。当前流行的方案有Hibernate与myBatis。两者各有优劣。竞争激烈其中一个比较重要的考虑的地方就是性能。因此笔者通过各种实验测出两个在相同情景下的性能相关的指数供大家参考。测试目标以下测试需要确定几点内容性能差异的场景性能不在同场景下差异比找出各架框优劣各种情况下的表现适用场景。测试思路测试总体分成单表插入关联插入单表查询多表查询。测试分两轮同场景下默认参数做一轮调优做强一轮横纵对比分析了。测试中尽保证输入输出的一致性。样本量尽可能大,达到10万级别以上减少统计误差。测试提纲具体的场景情况下插入测试110万条记录插入。查询测试1100万数据中单表通过id查询100000次,无关联字段。查询测试2100万数据中单表通过id查询100000次,输出关联对象字段。查询测试3100万*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) ENGINEInnoDB AUTO_INCREMENT1048561 DEFAULT CHARSETutf8user: 用户CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (id)) ENGINEInnoDB AUTO_INCREMENT524281 DEFAULT CHARSETutf8测试数据准备表一twitter无数据。表二user50万个随机的用户名。随机内容推特表(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-31from 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-31from MATERIAL实体代码EntityTable(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(materialTwittermaterialTwitter); 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(materialTwittermaterialTwitter); 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 idinsertTwitter keyPropertyid parameterTypeorg.pushio.test.show1.entity.Twitter useGeneratedKeystrue 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 idgetTwitterHasUser parameterTypelong resultTypeorg.pushio.test.show1.entity.Twitter select twitter.*,user.name as creteUserName from twitter,user where twitter.id#{id} AND twitter.add_user_iduser.idselect测试结果测试分析测试分成了插入单表查询关联查询。关联查询中hibernate分成三种情况进行配置。其中在关联字段查询中hibernate在两种情况下性能差异比较大。都是在懒加载的情况下如果推特对应的用户比较多时则性能会比仅映射100个用户的情况要差很多。换而言之如果用户数量少(关联的总用户数)时也就是会重复查询同一个用户的情况下则不需要对用户表做太多的查询。其中通过查询文档后证明使用懒加载时对象会以id为key做缓存也就是查询了100个用户后后续的用户信息使用了缓存使性能有根本性的提高。甚至要比myBatis更高。如果是关联50万用户的情况下,则hibernate需要去查询50万次用户信息,并组装这50万个用户此时性能要比myBatis性能要差不过差异不算大小于1ms表示可以接受。其中hibernate非懒加载情况下与myBatis性能差异也是相对其他测试较大平均值小于1ms。这个差异的原因主要在于myBatis加载的字段很干净没有太多多余的字段直接映身入关联中。反观hibernate则将整个表的字都会加载到对象中其中还包括关联的user字段。hibernate这种情况下有好有坏要看具体的场景对于管理平台需要展现的信息较多并发要求不高时hibernate比较有优势。然而在一些小活动互联网网站高并发情况下hibernate的方案太不太适合,myBatisVO则是首选。测试总结总体初观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 BootVue项目实战2、B站4小时上手MyBatis Plus3、一文搞懂前后端分离4、快速上手Spring BootVue前后端分离楠哥简介资深 Java 工程师微信号 southwindss《Java零基础实战》一书作者今日头条认证大VGitChat认证作者B站认证UP主(楠哥教你学Java)致力于帮助万千 Java 学习者持续成长。有收获就点个在看