zero 、 Preface
For ease of description , Let's abstract and simplify the project .
This is a front end for Angular、 For the back end Spring Project , project E-R One paragraph of the figure is as follows :
It's not hard to see. , Towns and communities are 1 Relationship to many .
When managing lower level areas , You need foreign keys associated with higher-level areas ( for example : The community must have a township )
Because the queries in these areas are very frequent , In order to reduce SQL frequency , Cache is set in the background .
In order to avoid the error of the whole system caused by deleting data , Soft deletion is enabled globally .
One 、 Problem recurrence
In the management page of any entity ( Such as township management ) Delete an object from ( Township ), The deleted data is no longer displayed in the list , You can also see in the database , Deleted objects deleted=1:
But in other entity Association queries ( When setting up towns in the community ), You can find the deleted objects , And it can be saved ...
( If you save the deleted data , It will cause the system to report an error )
Just to summarize :
Due to some problems with the project code , Soft deletion is normal in list paging query , But when foreign key association is needed , Soft deletion is invalid .
Two 、 Troubleshoot problems
Eliminate cache reasons
First of all, from the issue Look up , It may be caused by the back-end cache ( There have been similar problems before ). The backend is set to clear the cache when logging in again , So the test is simple .
Tried browser refresh 、 Sign out and log back in 、 Change browser and other operations , It didn't solve the problem , Now basically eliminate the cache reason .
Further investigation ,Spring Use in debug The internal code of the mode step-by-step query function , It is found that the deleted information appears in the return value
So far, it can be concluded that it is not The cache problem It's about the query method .
Check the calling relationship
Since there is a problem with the query , Why can deleted data be normally distinguished in the township list ?
With questions , I found the calling relationship between the front end and the back end :
Paging query initiated by township list , Finally call to findAll Method
And in the community -> Query the township in the township selector , It will eventually call findAll Method , But the parameters are different
// findAll No parameters
@Override
public List<Town> findAll() {
return (List<Town>) this.townRepository.findAll();
}
// page With parameters
@Override
public Page<Town> page(String name, Pageable pageable) {
return this.townRepository.findAll(TownSpecs.containingName(name)), pageable);
}
So the preliminary judgment , It's the warehouse floor TownRepository Of getAll() Method omits the function related to soft deletion , But in the code we have seen so far , There is no question about how soft deletion is implemented , So keep looking .
Explore the implementation of soft deletion
Now that we know what the problem is , Next, go to , In this project , How to realize soft deletion , And where are the key codes that affect the query of the warehouse layer , I start from the historical Pull Request Found soft deleted PR.
It is found that , All entities inherit the base entity , To enable soft deletion, you need to set deleted and deleteAt Field , And related Setter、Getter Method , Used to indicate deleted and deleted time :
Then add @SQLDelete annotation , Replace the delete function with ” Set up deleted=1“
The second line @where(clause = "deleted = false") The function is to query only the data that has not been soft deleted .
At this time, I came up with a stupid method : All on the warehouse floor findAll To add deleted = 0 Conditions , But the problem is , So many entities , A lot of duplicate code will be generated , And it didn't solve the problem fundamentally , So give up .
thus , After looking around, I still can't find the answer : Logically speaking, this can already take effect , What is it for? findAll() It will be abnormal ?
Compare the latest version of local code , It is found that the inherited entity has been deleted @where(clause = "deleted = false")
Just when I wonder , I found a think no link in the code comment , Open a look at the soft delete blog written by teacher pan , So I read it again .
spring boot Realize soft deletion
Only then did I realize :
@Where(clause = "deleted = false") Will cause us to carry on all or page When inquiring , Get one 500 EntiyNotFound error .
The blog also gives solutions : Create a SoftDeleteCrudRepository Interface , Inherit and override JPA Inside CrudRepository Methods , Manually add deleted = false Conditions ( See blog for specific code ), This can realize soft deletion and avoid 500 error .
3、 ... and 、 Untie BUG The veil of mystery
So you can guess , The problem must be that we wrote it ourselves SoftDeleteCrudRepository On , Probably because some methods do not override.
Come to the soft deletion warehouse of this project , About findAll Overloaded methods of have these :
@Override
public Page<T> findAll(Pageable pageable) {
return this.findAll(this.andDeleteFalseSpecification(null), pageable);
}
@Override
public Page<T> findAll(@Nullable Specification<T> specification, Pageable pageable) {
return super.findAll(this.andDeleteFalseSpecification(specification), pageable);
}
@Override
public List<T> findAll(@Nullable Specification<T> specification, Sort sort) {
return super.findAll(this.andDeleteFalseSpecification(specification), sort);
}
So let's go back a little bit , How to call the two cases just now :
// findAll No parameters
@Override
public List<Town> findAll() {
return (List<Town>) this.townRepository.findAll();
}
// page With parameters
@Override
public Page<Town> page(String name, Pageable pageable) {
return this.townRepository.findAll(TownSpecs.containingName(name)), pageable);
}
good , Solved the case , Our soft delete class does not override Empty parameter findAll Method , So for empty parameters , It doesn't automatically add deleted=1 Query criteria for .
So just add :
@Override
public List<T> findAll(@Nullable Specification<T> specification) {
return super.findAll(this.andDeleteFalseSpecification(specification));
}
You can make the bug In all warehouses findAll() Methods disappear , In the future, there will be new calling methods , Just modify the soft delete class .
At this point, the problem is finally solved .
Reference material
- spring boot Realize soft deletion :https://segmentfault.com/a/11...
Postscript
In fact, this project is really The writing method is more complicated than that in the references :
- SoftDeleteCrudRepository No longer an interface , Instead, the implementation class
- Other warehouses do not inherit directly SoftDeleteCrudRepository, Instead, use factory mode injection
- I don't understand the code of factory mode in the project , In fact, I didn't understand it in the end , Are there any other warehouses extends either implements Under the circumstances , How to call SoftDeleteCrudRepository Of .
Copyright notice
The author of this article : Dream cloud intelligence development team of Hebei University of technology - Liu Yuxuan
New people are inexperienced , If you have suggestions, welcome to exchange , If there are mistakes, please spray lightly