MybatisPlus uses saveOrUpdate in detail (use with caution), and problem solving & mysql save or update ON DUPLICATE KEY UPDATE

Today's idea is that when inserting into the database, if the value of a certain main field is repeated, it will not be inserted, otherwise it will be inserted!
I took a look at mybatis-Plus and there is this saveOrUpdate method!

There was no problem when using save originally, but after changing to saveOrUpdate, an error was reported after a while.

com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: error: can not execute. because can not find column for id from entity!

It is this mybatisPlus that cannot find which is the primary key field, because this saveOrUpdate performs operations based on the primary key by default!

All need to put @TableId on the primary key header of the original entity class, as follows, followed by the fields corresponding to the database, and the primary key has been automatically incremented.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Subject {
    
    

  @TableId(value = "subject_Code", type = IdType.AUTO)
  private long subjectCode;

  private String subjectNameCn;

  private String subjectNameEn;

  private String subjectHref;

  private long subjectParentCode;

  private long levelCode;

  private int isDelete;

  private long operateTimestamp;


}

But there is still a problem, that is, this operation is based on the primary key, but my primary key is automatically incremented, and there will be no problem. The next step is to find a way to let him operate according to the specified field. It seems that there is one provided. mouth.

// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);

I'll see how it works again!

After researching and trying for a long time, I finally came up with it. Maybe few people will do it like me! So I tried it myself.

When saveOrUpdate does not use the conditional constructor, it will first perform a query based on the primary key. If the found result is 0, then the insert operation will be performed. If the found result is not 0, the update operation will be performed.

But under normal circumstances, the primary key will not be repeated! All I use conditional constructor Wrapper!

UpdateWrapper<Subject> subject_name_cn = new UpdateWrapper<Subject>()
			.eq("subject_Name_Cn", subjectNameCn);
subjectService.saveOrUpdate(subject,subject_name_cn );

The result of this change is that the modification will be executed first. If one is executed, the execution will be successful. If the execution result is 0, then the query will be executed according to the primary key, and then the insert operation will be performed!

In fact, it feels a bit unnecessary, because since the results have not been updated, then there must be no such field!

But after thinking about it, you don't have a specified field, and it's not that you don't have a primary key!

But the primary key auto-increment is definitely not there!

So I thought of a coquettish operation, what would happen if I passed QueryWrapper instead of UpdateWrapper!

Will it be added to the query condition? I threw it in without reporting an error, I was a little excited, and I don't know the result!

QueryWrapper<Subject> subject_name_cn1 = new QueryWrapper<Subject>()
                    .eq("subject_Name_Cn", subjectNameCn);
subjectService.saveOrUpdate(subject,subject_name_cn1);

All right! Come up and give me an update! No mercy! I deleted the data and tried again!

All right! Of course and eggs! Disillusioned! There is no difference with the pass UpdateWrapper! ~ Farewell!

After looking at the source code, the default parameter is Wrapper type, and then updated according to the conditional constructor,

Returns on success,

If unsuccessful, use the method of the unconditional constructor.

default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
    
    
    return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}

I feel that a type judgment should be added!

 if(updateWrapper instanceof QueryWrapper){
    
    
 	去拼接查询语句!
 }
  if(updateWrapper instanceof UpdateWrapper){
    
    
 	去拼接更新语句!
 }

In this way, it will not be checked only based on ID!


I finally understand~

Why use updateWrapper!

The difference between it and queryWrapper is.

updateWrapper uses set to set the modified data.

queryWrapper uses select to set the data to be checked out.

Haha, this is still very important!


Does saveOrUpdate have a mapping id

We know that mybatis will map the id when inserting, but what if it is saveOrUpdate?

For example, after I saveOrUpdate(), I need to use his id, but the object I passed in does not have an id.

 @Test
 void saveOrUpdate(){
    
    
       UserText userText = new UserText();
       userText.setUserSex(Sex.MAN);
       boolean b = userTextService.saveOrUpdate(userText);
       System.out.println(userText.getUserId());
   }

It can be seen that he first checks through the id and then inserts it, and then returns a new id.

==>  Preparing: SELECT user_id,user_name,user_sex,start_time FROM user_text WHERE user_id=?
==> Parameters: 0(Long)
<==      Total: 0
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6d0fe80c]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6d0fe80c] from current transaction
==>  Preparing: INSERT INTO user_text ( user_sex ) VALUES ( ? )
==> Parameters: 1(Integer)
<==    Updates: 1

But this update, I find it difficult to do without trying, because if you don’t have an id, then you pass in the value of this object, and you may find out multiple objects, so which id should be mapped back, right?

@Test
void saveOrUpdate(){
    
    
     UserText userText = new UserText();
     userText.setUserSex(Sex.MAN);
     UpdateWrapper<UserText> objectUpdateWrapper = new UpdateWrapper<UserText>()
             .eq("user_sex",Sex.MAN);
     boolean b = userTextService.saveOrUpdate(userText,objectUpdateWrapper);
     System.out.println(userText.getUserId());
 }

But try again, when we added an UpdateWrapper, it was successfully executed, 3 items were executed, and the id was returned as 0.

But this time I added a wrapper, and I will try again, what will happen if only one is inserted. Haha, if you don’t read the source code to debug, you can only try this, no wonder.

Hey, that's right, I'll go and look at the source code first, to see if I can see any tricks.

It seems that I have read the source code before. Two methods with different structures have different execution logics.

boolean saveOrUpdate(T entity);	

default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
    
    
	return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}

The difference is not big, that is, one more update step will be performed. If the execution is successful, it will go directly. If the execution is unsuccessful, saveOrUpdate will be done according to this object.

Go in and look through, if the value is found through the id, it will be updated according to the id, otherwise it will be added.

So there is no need to try it, let's write one by hand, if you need to return the id.

Use with caution!

If you think about it carefully, when you are the data automatically generated by the primary key, you must write UpdateWrapper, otherwise you must always insert it! It will not be updated at all, because the default is to query by id.

The data generated by the primary key generally does not write an id, so ah! Check it out now!


UpdateWrapper Tips

Although it is written above that updateWrapper can write a set attribute, there are two situations.

First of all, we have an object with 5 attributes, only 4 have values, and 1 has no value.

When mybatis-plus is executed, it will first check which attribute of your object has a value and which one does not.

Only attributes with values ​​​​will be updated, so only 4 attributes will be updated, and the other attribute will not leave him empty.

If you only want to change one attribute, you can also write one more set, but it doesn't feel necessary, but it is more flexible.
If you want to write another value, you can write it into the set.


2021-05-21 13:31:32

I found a very rubbish one. The set of updateWrapper I bragged about is so awesome. In fact, I thought it was too beautiful. It just added another field to the original one! I vomited!

UpdateWrapper<GameScorePo> updateWrapper = new UpdateWrapper<GameScorePo>()
                   .eq("game_id",gameScorePo.getGameId())
                   .eq("team_id",gameScorePo.getTeamId())
                   .eq("quarter",gameScorePo.getQuarter())
                   .set("score",gameScorePo.getScore());

           gameScoreService.saveOrUpdate(gameScorePo,updateWrapper);

The result of such execution is this!

insert image description here
Two scores, I vomited!

Could it be that my opening posture is wrong?

Check it out to see what happened to this set

insert image description here
Just don't throw the object, throw an empty object, so that you can set it!

A separate set is easy to use, but it is not easy to use in saveOrUpdate! Let's go according to your needs!




INSERT INTO pms_statistic (
	id,
	tenantId,
	tenantName,
	isDeleted,
	createTime
)
VALUES
	(
		6257,50,'保存或修改0',1,'2020-01-00'
	) ,(
		6258,51,'保存或修改1',1,'2020-01-01'
	) ,(
		6259,52,'保存或修改2',1,'2020-01-02'
	) ,(
		62510,53,'保存或修改3',1,'2020-01-03'
	) 
ON DUPLICATE KEY UPDATE tenantId = VALUES(tenantId),tenantName = VALUES(tenantName)
		,isDeleted = VALUES(isDeleted),createTime = VALUES(createTime);

This statement is used based on the primary key (PRIMARY KEY) or unique index (UNIQUE INDEX).
Update if the unique identifier or primary key already exists (display the value of the affected row: 2)

Insert as a new row if the unique identifier or primary key does not exist (show value for affected rows: 1)

As above: If the id (6257, 6258, 6259, 62510) exists, update the field data after ON DUPLICATE KEY UPDATE according to the id (tenantId = VALUES(tenantId), tenantName = VALUES(tenantName), isDeleted = VALUES(isDeleted), createTime = VALUES(createTime))

Before executing sql (6257id exists, other ids do not exist)

after execution

6257 modified, 6258, 6259, 62510 inserted

Affected lines: 5 (insert 3 lines, modify 1 line (the modification is two lines))

Note: ON DUPLICATE KEY UPDATE is just MySQL's unique syntax, not SQL standard syntax!

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/131609927