当前位置:网站首页>Redis (IV) redis association table caching
Redis (IV) redis association table caching
2022-06-26 10:41:00 【My name is 985】
In the project , If there is no association between tables , There is no problem with using cache in this way . If there is an association relationship between tables , How to solve the cache problem ?
Here is a demonstration to illustrate the problem , Now there is student and school modular .
1、 Create table
1.1 school
CREATE TABLE `school`
(
`id` varchar(255) NOT NULL COMMENT ' Primary key ',
`name` varchar(255) DEFAULT NULL COMMENT ' School name ',
PRIMARY KEY (`id`)
)
1.2 student
CREATE TABLE `student` (
`id` varchar(255) NOT NULL COMMENT ' Primary key ',
`name` varchar(255) DEFAULT NULL COMMENT ' The student's name ',
`school_id` varchar(255) DEFAULT NULL COMMENT ' School id',
PRIMARY KEY (`id`)
)
2. establish vo
2.1 SchoolVo
@Data
public class SchoolVo {
/** Primary key */
private String id;
/** School name */
private String name;
/** Student list */
private List<StudentVo> studentList;
}
2.2 StudentVo
@Data
public class StudentVo {
/** Primary key */
private String id;
/** School name */
private String name;
/** School vo */
private SchoolVo schoolVo;
}
3. Interface
3.1 SchoolService
@Service("schoolService")
public class SchoolServiceImpl implements ISchoolService {
@Override
@Cacheable(cacheNames = "school", key = "#schoolId")
public SchoolVo getSchoolVoById(String schoolId){
// Query data
School school = schoolDao.getById(schoolId);
List<Student> studentList = studentService.findStudentBySchoolId(schoolId);
// structure vo
SchoolVo schoolVo = _BeanUtil.copyProperties(school, SchoolVo.class);
schoolVo.setStudentList(_BeanUtil.copyList(studentList, StudentVo.class));
return schoolVo;
}
}
3.2 StudentService
@Service("studentService")
public class StudentServiceImpl implements IStudentService {
@Override
@Cacheable(cacheNames = "student", key = "#studentId")
public StudentVo getStudentVoById(String studentId){
// Query data
Student student = studentDao.getById(studentId);
School school = schoolService.getSchoolById(student.getSchoolId());
// structure vo
StudentVo studentVo = _BeanUtil.copyProperties(student, StudentVo.class);
SchoolVo schoolVo = _BeanUtil.copyProperties(school, SchoolVo.class);
studentVo.setSchoolVo(schoolVo);
return studentVo;
}
}
4. Table associated cache update problem
Come here , You can find a problem : although getSchoolVoById and getStudentVoById But you can cache , however getSchoolVoById cache school At the same time as the object , It also caches the associated student.
So imagine the following , If you pass schoolService.update/delete Interface modification / Deleted school; Or by studentService.add/update/delete New interface / modify / Deleted student, And then call getSchoolVoById Interface , The cached data obtained is problematic .
The simplest solution, of course, is to schoolService.update/delete or studentService.add/update/delete When , Delete the associated cache school::id. But it is obviously not efficient , Because even if I made a small change , For example, it was modified school Of one of the students name, And the whole school::id Delete . And even harder , As the number of associated tables between tables increases , There will be more and more associated caches to delete , It will become more and more important to maintain the real-time delete cache , And the efficiency of the system will be slower and slower .
5. Solutions and ideas
The author draws lessons from mysql Thought , stay mysql in , Table to table Association , Even if a table is modified or deleted , adopt left join And so on , You can also get the latest data immediately . because mysql yes Dynamic association through primary key and foreign key in real time Get up , Instead of caching the entire associated query results ; And the records of a table are modified or deleted , Only the records of the modified table will be modified or deleted , It does not affect the records of the associated table .
According to the idea above , To solve the problem of updating the associated table cache , There are two main points
One is mysql It is stored in a single table , that redis One group, too key Corresponding to a table
Two is mysql stay select It is a real-time dynamic association between primary keys and foreign keys , So we are getting vo It also needs to be dynamically associated with the primary key and foreign key in real time . But how do we implement dynamic correlation ? Obviously, simply use redis It's impossible , It should be through java To achieve . In addition, you can think that the database many to many relationship will create an associated table to save the many to many relationship , But the top one student and school It's a one-to-many relationship , So how to achieve ?! In fact, for one to many relationships, you can also create a new relationship table to store the associated relationships ! So we just need to be redis Open a new group key To preserve student and school Correlation relation of , Can't it be realized ?
6.redis Cache structure design
Through the above ideas , Make the following redis key-value The design of the
| redis Of key | redis Of value |
|---|---|
| school::{id} | {id: “”, name: “”} school object |
| student::{id} | {id: “”, name: “”, schoolId:“”} student object |
| school::{id}::student | [studentId1, studentId2, studentId3…] school Medium student |
{id} Real for data id.
The example given in this article is a one to many relationship . When many to many , It can be split into two-way one to many .
7. Dynamically return according to the cache vo
The implementation code is as follows , Follow sql equally , When querying associated query results , It does not cache the associated query results , It is a dynamic link association , Last assemble Output the correlation result
@Service("schoolService")
public class SchoolServiceImpl implements ISchoolService {
@Override
public SchoolVo getSchoolVoByIdInCache(String id, boolean isNeedStudent) throws Exception {
//1. According to the reference id, matching "school:id", find school( Go cache )
ISchoolService _this = _SpringContextUtil.getBean(ISchoolService.class);
School school = _this.getSchoolById(id);
if(null == school){
return null;
}
SchoolVo schoolVo = _BeanUtil.copyProperties(school, SchoolVo.class);
if(isNeedStudent){
// 2. according to school:id:student, Find the relevant studentId( Go cache )
String schoolStudentKey = _CacheKeyUtil.getSchoolStudentKey(school.getId());
List<String> studentIds = ObjectUtil.defaultIfNull(
stringRedisTemplate.opsForList().range(schoolStudentKey, 0, -1),
new ArrayList<>(0));
// 3. according to studentId, find student( Go cache )
List<StudentVo> studentVoList = new ArrayList<>(studentIds.size());
for (String studentId : studentIds) {
StudentVo studentVo = studentService.getStudentVoByIdInCache(studentId, false);
studentVoList.add(studentVo);
}
// 4. structure Vo Return value (vo Not cached )
schoolVo.setStudentList(studentVoList);
}
return schoolVo;
}
@Cacheable(cacheNames = School.cacheName, key = "#id")
@Override
public School getSchoolById(String id) {
return schoolDao.getById(id);
}
}
@Service("studentService")
public class StudentServiceImpl implements IStudentService {
@Override
public StudentVo getStudentVoByIdInCache(String id, boolean isNeedSchool) throws Exception {
// 1. According to the reference id, matching "student:id", find student( Go cache )
IStudentService _this = _SpringContextUtil.getBean(IStudentService.class);
Student student = _this.getStudentById(id);
if(null == student){
return null;
}
StudentVo studentVo = _BeanUtil.copyProperties(student, StudentVo.class);
// 2. according to schoolId, matching "school:schoolId", find school( Go cache )
if (isNeedSchool) {
String schoolId = student.getSchoolId();
if(StrUtil.isNotBlank(schoolId)){
SchoolVo schoolVo = schoolService.getSchoolVoByIdInCache(schoolId, false);
studentVo.setSchoolVo(schoolVo);
}
}
// 3. structure Vo Return value (vo Not cached )
return studentVo;
}
@Cacheable(cacheNames = Student.cacheName, key = "#id", unless = "#result == null")
@Override
public Student getStudentById(String id){
return studentDao.getById(id);
}
}
8. Assembly cache returns Vo The benefits of
In addition 、 modify 、 You do not need to delete the associated cache when deleting , Speed up efficiency ! And especially for modification operations , Just modify your own table and cache , There is no need to manipulate other caches .
student Add, delete and change operation
- When student When it's added , Just add student Record 、 cache student::id. In the school::{id}::student Last push At present studentId
- When student When it's modified , It just needs to be modified student Record and refresh cache school::id that will do , There is no need to delete the associated cache
- When student When it's deleted , Just delete student Record 、 Delete cache school::id、 And in school::student Delete the current studentId
school Add, delete and change operation
- When school When it's added , Just add school Record 、 cache school::id
- When school When it's modified , It just needs to be modified school Record and refresh cache school::id that will do , There is no need to delete the associated cache
- When school When it's deleted , Just delete student Record 、 Delete cache school::id, And delete school::student Entire cache
9. thank
I hope this article is helpful and enlightening , You are also welcome to leave a message below to give more different solutions , If this article helps you , Please give me some praise + Focus on ~
边栏推荐
猜你喜欢

OpenCV图像处理-灰度处理

Under the double reduction, the amount of online education has plummeted. Share 12 interesting uses of webrtc

Problems encountered in the application and development of Hongmeng and some roast
![Installing MySQL under Linux [details]](/img/38/77be56c3ef3923ce4c4e5df4a96f41.png)
Installing MySQL under Linux [details]

利用foreach循环二维数组

MySQL seventh job - update data

Little red book - Summary of internal sales spike project

MySQL第十一作業-視圖的應用

String constant pool, class constant pool, and runtime constant pool

Reshape a two-dimensional array with 3 rows and 3 columns to find the sum of the diagonals
随机推荐
二叉树常见面试题
Common interview questions of binary tree
MySQL 9th job - connection Query & sub query
Appium automation test foundation - mobile end test environment construction (II)
Express (I) - easy to get started
SQL Server foundation introduction collation
The IE mode tab of Microsoft edge browser is stuck, which has been fixed by rolling back the update
Global and Chinese markets in hair conditioner 2022-2028: Research Report on technology, participants, trends, market size and share
Postman入门教程
Installer MySQL sous Linux [détails]
Opencv image processing - grayscale processing
【無標題】
VS或Qt编译链接过程中出现“无法解析的外部符号”的原因:
MySQL第八次作业
Global and Chinese market of aluminum sunshade systems 2022-2028: Research Report on technology, participants, trends, market size and share
2. merge two ordered arrays
【Leetcode】76. Minimum covering substring
8- creating leecode algorithm with pictures and texts - algorithm solution of minimum stack and LRU caching mechanism
MySQL第十次作业-视图
MySQL Chapter 5 Summary