Mybatis vs hibernate, which performance is better?

Java technology stack 2021-09-15 10:02:26

author : Zheng muxing <br> source :https://zhuanlan.zhihu.com/p/21966051

Preface

Because the programming idea is different from the database design pattern , Some of them have been born ORM frame .

The core is to transform relational database and data into object type . The current popular solutions are Hibernate And myBatis.

Both have advantages and disadvantages . Competition is fierce , One of the more important considerations is performance .

So the author through various experiments , Two performance related indices under the same scenario are measured , For your reference .

Friendship tips : If you think the article is too long , You can pull to the end of the text to see the conclusion .

Test target

The following test needs to determine a few points :

Performance difference scenarios ;

Performance is not different in the same scenario ;

Find out the advantages and disadvantages of each frame , Performance in various situations , Applicable scenario .

Test ideas

The test population is divided into : Single table insert , Association insertion , Single table query , Multi-table query .

There are two rounds of testing , Do one round with the default parameters in the scene , A round of tuning and strengthening , This paper makes a comparative analysis of .

Ensure the consistency of input and output in the test .

The sample size should be as large as possible , achieve 10 Above 10000 level , Reduce statistical error .

Test outline

In specific scenarios

Insert the test 1:10 Ten thousand records are inserted into .

Query test 1:100 In ten thousand data, the single table passes through id Inquire about 100000 Time , No associated fields .

Query test 2:100 In ten thousand data, the single table passes through id Inquire about 100000 Time , Output associated object field .

Query test 3:100 ten thousand *50 Million linked data query 100000 Time , Both output the same fields .

Get ready

database :mysql 5.6

Form design :

twitter: 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: 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

Test data preparation :

Table 1 :twitter

No data .

Table two :user

50 10000 random user names .

Random content tweets (material_twitter)

nothing id, Only random string content , common 10 Ten thousand .

Used to insert control tweet table .

Generate data code , relation 100 Users :

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

Generate data code , relation 500000 Users :

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 code

@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;
}
}

Start

Insert the test 1

Code operation :

Load random content twitter table data into memory , And then, one by one, they add to the twitter list , common 10 Ten thousand .

Key code :

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 code snippet :

<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>

Query test 1

adopt id from 1 Increase to 10 Wan queries twitter content in turn , Only output microblog content .

Key code :

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());
}

Query test 2

And query testing 1 The whole thing is the same , Add the creator name field of microblog , Here we need to associate .

The corresponding microblog is 10 Million users . Maybe some users repeat . The corresponding number of users here may be the same as hibernate The configuration of lazy loading has an impact on .

This shows hibernate A convenient place for , You can go directly through getAddUser() You can get user Related fields .

However myBatis You need to write a new vo, So testing batis When it comes to Twitter Add the name of the creator to the entity (createUserName).

here hibernate Will test for lazy loading respectively , No lazy loading .

mybatis Will test both default and cache conditions .

among mybatis It is difficult to configure the cache mechanism of , Not for real business ( There may be dirty data ), This is for reference only .

When testing , There are two scenarios for the number of users associated with twitter , One is that Twitter is associated with 100 Users , It's different tweets, which are in 100 Within users , The correlation here is generated randomly .

The other is that Twitter is associated with 50 Million users , Basically 50 The information of each user will be found out .

Above “ Get ready ” You can see how the associated data is generated in .

Key code :

hibernate:

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

Load configuration changes quickly ,Twitter.java:

@ManyToOne(fetch = FetchType.EAGER)// Emergency loading 
//@ManyToOne(fetch = FetchType.LAZY)// Lazy loading 
@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 To configure :

<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>

test result

Test and analysis

The test is divided into inserts , Single table query , Relational query . Association query hibernate Configure it in three situations .

In the associated field query ,hibernate In two cases , There is a big difference in performance . In the case of lazy loading , If Twitter has more users , Then the performance is better than just mapping 100 The situation of individual users is much worse .

In other words , If the number of users is small ( Total number of associated users ) when , In other words, the same user will be queried repeatedly , You don't need to do too many queries on the user table .

After querying the document , Prove that when using lazy loading , The object will be id by key Do the cache , That is to say, to inquire about 100 After users , Subsequent user information is cached , Make the performance have fundamental improvement . Even better than myBatis Higher .

If it's a connection 50 Million users , be hibernate Need to check 50 Ten thousand user information , And assemble this 50 Million users , At this point, the performance is better than myBatis Poor performance , But the difference is not big , Less than 1ms, Indicates acceptable .

among hibernate In the case of non lazy loading, and myBatis The performance difference is also larger than other tests , The average is less than 1ms.

The main reason for this difference is ,myBatis The loaded fields are clean , There are not too many extra fields , Directly reflected in the Association . take the reverse into consideration hibernate Then the word of the whole table will be loaded into the object , It also includes related user Field .

hibernate There are good and bad in this situation , It depends on the specific scene , For the management platform , There's more information to show , When concurrency requirements are not high ,hibernate Comparative advantage .

However, in some small activities , Internet sites , High concurrency ,hibernate It's not very suitable for ,myBatis+VO Is the preferred .

in addition , Official account Java Technology stack , Reply in the background : interview , I can get the MyBatis A series of interview questions and answers , Very complete .

Test summary

The overall view ,myBatis In all cases , Especially insert and single table query , Will be slightly better than hibernate. But the difference is not obvious , You can basically ignore the difference .

The big difference is when the association query ,hibernate In order to ensure POJO Data integrity , The associated data needs to be loaded , More data needs to be queried additionally . here hibernate It doesn't provide the corresponding flexibility .

A big difference in association is the lazy loading feature . among hibernate You can make special use of POJO Integrity to cache , You can save objects in the first and second level caches , If there are more queries on a single object , There will be obvious performance benefits .

When it comes to single object association , The performance can be improved by lazy loading and secondary caching .

Last , Performance and query of data orm The framework doesn't matter much , because orm It mainly helps developers transform relational data into object data model , On the deep analysis of the code ,hibernate Designed to be more heavyweight , For development, it can be regarded as redevelopment of a database , Don't let developers care too much about database features , Directly in hibernate On the basis of development , Execution is divided into sql Generate , Data encapsulation, etc , It took a lot of time here . However myBatis It's more direct than , It is mainly to do a mapping between association and output fields . among sql It's basically written , You can replace it directly , No need to be like hibernate That's how to dynamically generate the whole sql sentence .

Fortunately hibernate At this stage, it has been optimized better , There's nothing like myBatis There are too many differences in performance , But in terms of development efficiency , Scalability is relative to myBatis It's too much to say .

Last, last , About myBatis cache ,hibernate Wait a minute , I'll do a special test later .

About cache configuration

myBatis relative Hibernate And the package is more tight ORM In terms of implementation , because hibernate The operation of data objects is tightly encapsulated , It can guarantee the cache synchronization within its scope , and ibatis What is provided is a semi enclosed encapsulation implementation , Therefore, it is difficult to synchronize the cache automatically .

The above cache configuration test is only for performance analysis , There's no usability case , because myBatis If you configure the cache directly , Dirty data may appear ,.

In the case of associated query data ,hiberntae It's a better solution to load lazily with L2 cache ( No dirty data ), Also with myBatis Compared with the obvious advantages . In this situation , Performance and myBatis flat .

In the real world ,myBatis Caching may not be configured on this site , There will be dirty data , So it's very likely that hibernate Performance will be better .

Recent hot article recommends :

1.1,000+ Avenue Java Arrangement of interview questions and answers (2021 The latest version )

2. Don't fill the screen again if/ else 了 , Try strategy mode , It's delicious !!

3. Oh my god !Java Medium xx ≠ null What is the new grammar ?

4.Spring Boot 2.5 Blockbuster released , Dark mode is too explosive !

5.《Java Development Manual ( Song Mountain version )》 The latest release , Download it quickly !

I think it's good , Don't forget to like it + Forward !

Please bring the original link to reprint ,thank
Similar articles

2021-09-15

2021-09-15

2021-09-15

2021-09-15

2021-09-15