+ Redis cache write timing of high-performance database function thumbs

Based SpringCloud, the user initiates a thumbs up, thumbs canceled after the first deposit Redis, and then two hours to read the data written to the database thumbs do every Redis from persistent storage.

The thumbs up function in many systems have, but do not look features a small, pretty much do what you want to consider.

Thumbs up, thumbs cancel the high frequency of operation is, if every time the database to read and write, a lot of action will affect database performance, so it is necessary to do caching.

As for how long to take time from data stored in the database Redis, according to the actual situation of a given project, and I was temporarily located two hours.

View all who need to project requirements thumbs up, thumbs so to store each person's thumbs up, thumbs are people, simply do not count.

The article describes four parts:

Redis cache design and implementation of
database design
database operation
opening timing of the tasks stored in the database persistent
a, Redis cache design and realization

1.1 Redis installation and operation

Redis installation please refer to their own tutorials.
He said at Docker installation and operation Redis

docker run -d -p 6379: 6379 redis : 4.0.8
If Redis is already installed, open a command line, enter the command to start the Redis

redis-server
integration with SpringBoot 1.2 Redis project

1. Introducing a dependency in pom.xml

<dependency>
<the groupId> org.springframework.boot </ the groupId>
<the artifactId> Starter-Spring-Boot-Data-Redis </ the artifactId>
</ dependency>
2. add comments on startup class @EnableCaching

@SpringBootApplication
@EnableDiscoveryClient
@EnableSwagger2
@EnableFeignClients(basePackages = "com.solo.coderiver.project.client")
@EnableCaching
public class UserApplication {

public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
3.编写 Redis 配置类 RedisConfig

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import java.net.UnknownHostException;


@Configuration
public class RedisConfig {

@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {

Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);

RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}


@Bean
@ConditionalOnMissingBean (StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate (
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate new new StringRedisTemplate Template = ();
template.setConnectionFactory (redisConnectionFactory);
return Template;
}
}
Thus Redis disposed SpringBoot projects have been completed, It is pleasant to use.

1.3 Redis type of data structure

Redis can store the mapping between keys and 5 different types of data structures, these five types of data structures are String (String), List (list), the Set (set), the Hash (hash) and zset (orderly set).

The following data structure to these five types of brief description:


Like Redis 1.4 points in the data storage format

Redis store two kinds of data with a recording point Like people, who were thumbs, thumbs state data, each user is the other point is how many times the like, to be a simple count.

Like recording dots due to the need and the thumbs are people, little Like state (point Like cancel thumbs), but also to remove fixed time interval Redis Like all data points, are analyzed under the Hash Redis data format most suitable.

Hash is because the data in the presence of a key where you can easily put all the data points like this are taken by this key. This key data can also be stored inside the form of key-value pairs, into convenient point Like people, the thumbs and the thumbs state.

Like set point for the person id likedPostId, the id of the human thumbs likedUserId, thumbs when the state is 1, 0 is canceled state thumbs. Like the point and the point Like human person id id as a key intermediate with :: id two spaced points Like state as value.

Like if the user points, the key is stored: likedUserId :: likedPostId, corresponding to a value of 1. Like cancel point, the key is stored: likedUserId :: likedPostId, corresponding to a value of 0. Data fetch the key is obtained with the two cut :: id, it is also very convenient. (Redis common interview questions, can be found here)

See in the visualization tool RDM is like this

 

1.5 Operating Redis

The specific operation method encapsulated in the interface to the RedisService

RedisService.java

import com.solo.coderiver.user.dataobject.UserLike;
import com.solo.coderiver.user.dto.LikedCountDTO;

import java.util.List;

public interface RedisService {

/ **
* thumbs up. State. 1
* @param likedUserId
* @param likedPostId
* /
void saveLiked2Redis (likedUserId String, String likedPostId);

/ **
* Cancel thumbs up. The state is changed to 0
* @param likedUserId
* @param likedPostId
* /
void unlikeFromRedis (likedUserId String, String likedPostId);

/ **
* Delete a thumbs up data from the Redis
* @param likedUserId
* @param likedPostId
* /
void deleteLikedFromRedis (likedUserId String, String likedPostId);

/ **
* Like the number of points added to the user. 1
* @param likedUserId
* /
void incrementLikedCount (String likedUserId);

/ **
* Like the number of points minus the user. 1
* @param likedUserId
* /
void decrementLikedCount (String likedUserId);

/ **
* Like obtain all the data points stored Redis
* @return
* /
List <UserLike> getLikedDataFromRedis ();

/ **
* Get the number of points for all stored Redis Like
* @return
* /
List <LikedCountDTO> getLikedCountFromRedis ();

}
Implementation class RedisServiceImpl.java

import com.solo.coderiver.user.dataobject.UserLike;
import com.solo.coderiver.user.dto.LikedCountDTO;
import com.solo.coderiver.user.enums.LikedStatusEnum;
import com.solo.coderiver.user.service.LikedService;
import com.solo.coderiver.user.service.RedisService;
import com.solo.coderiver.user.utils.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

@Autowired
RedisTemplate redisTemplate;

@Autowired
LikedService likedService;

@Override
public void saveLiked2Redis(String likedUserId, String likedPostId) {
String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.LIKE.getCode());
}

@Override
public void unlikeFromRedis(String likedUserId, String likedPostId) {
String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.UNLIKE.getCode());
}

@Override
public void deleteLikedFromRedis(String likedUserId, String likedPostId) {
String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId);
redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
}

@Override
public void incrementLikedCount(String likedUserId) {
redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, 1);
}

@Override
public void decrementLikedCount(String likedUserId) {
redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1);
}

@Override
public List<UserLike> getLikedDataFromRedis() {
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
List<UserLike> list = new ArrayList<>();
while (cursor.hasNext()){
Map.Entry<Object, Object> entry = cursor.next();
String key = (String) entry.getKey();
//分离出 likedUserId,likedPostId
String[] split = key.split("::");
String likedUserId = split[0];
String likedPostId = split[1];
Integer value = (Integer) entry.getValue();

//组装成 UserLike 对象
UserLike userLike = new UserLike(likedUserId, likedPostId, value);
list.add(userLike);

// save to list after being removed from the Redis
redisTemplate.opsForHash () Delete (RedisKeyUtils.MAP_KEY_USER_LIKED, Key);.
}

return list;
}

@Override
public List <LikedCountDTO> getLikedCountFromRedis () {
the Cursor <of Map.Entry <Object, Object >> Cursor = redisTemplate.opsForHash () Scan (RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);.
List <LikedCountDTO> = new new List the ArrayList < > ();
the while (cursor.hasNext ()) {
of Map.Entry <Object, Object> cursor.next Map = ();
// Like the number of points stored in LikedCountDT
String Key = (String) map.getKey ();
DTO = new new LikedCountDTO LikedCountDTO (Key, (Integer) map.getValue ());
List.add (DTO);
// this is deleted from the record Redis
redisTemplate.opsForHash () delete (RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, Key);.
}
List return;
}
}
used tools and enumerated classes

RedisKeyUtils, for generating a key in accordance with certain rules

public class RedisKeyUtils {

// save user data thumbs Key
public static String MAP_KEY_USER_LIKED Final = "MAP_USER_LIKED";
// save the user the number of thumbs Key
public static String MAP_KEY_USER_LIKED_COUNT Final = "MAP_USER_LIKED_COUNT";

/ **
* splice is thumbs up and thumbs of the user id of the person's id as key. Formats :: 333333 222222
* @param likedUserId the human thumbs ID
* @param likedPostId human thumbs ID
* @return
* /
public static String getLikedKey (likedUserId String, String likedPostId) {
the StringBuilder the StringBuilder Builder new new = ();
builder.append (likedUserId);
builder.append ( "::");
builder.append (likedPostId);
return builder.toString ();
}
}
enumeration class LikedStatusEnum user state thumbs

package com.solo.coderiver.user.enums;

import lombok.Getter;

/ **
* user's thumbs state
* /
@Getter
public enum {LikedStatusEnum
the LIKE (. 1, "thumbs up"),
that Unlike (0, "thumbs cancellation / non-point like"),
;

private Integer code;

private String msg;

LikedStatusEnum (code Integer, String MSG) {
this.code = code;
this.msg MSG =;
}
}
Second, the database design

Database table comprises at least three fields: the thumbs user id, user thumbs id, thumbs state. Coupled with the primary key id, creation time, modification time on the line.

Construction of the table statement

Table `user_like` Create (
` id` int Not null AUTO_INCREMENT,
`liked_user_id` VARCHAR (32) Not null Comment 'thumbs being user id',
` liked_post_id` VARCHAR (32) Not null Comment 'thumbs of the user id' ,
`status` tinyint (1) default '1' the Comment 'thumbs state, 0 canceled, 1:00 Chan',
` create_time` timestamp not null default CURRENT_TIMESTAMP the Comment 'creation time',
`update_time` timestamp not null default CURRENT_TIMESTAMP ON Update current_timestamp comment 'modified',
Primary Key ( `id`),
the INDEX liked_user_id`` ( `liked_user_id`),
the INDEX liked_post_id`` ( `liked_post_id`)
) Comment 'Like user point table';
object corresponding UserLike

import com.solo.coderiver.user.enums.LikedStatusEnum;
import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/ **
* Like user point table
* /
@Entity
@Data
public class UserLike {

//主键id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

// the user's point Like the above mentioned id
Private String likedUserId;

// thumbs users the above mentioned id
Private String likedPostId;

// default state thumbs not thumbs
private Integer status = LikedStatusEnum.UNLIKE.getCode ();

public UserLike() {
}

public UserLike(String likedUserId, String likedPostId, Integer status) {
this.likedUserId = likedUserId;
this.likedPostId = likedPostId;
this.status = status;
}
}
三、数据库操作

Also in the operation of the database interface package

LikedService

import com.solo.coderiver.user.dataobject.UserLike;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

public interface LikedService {

/**
* 保存点赞记录
* @param userLike
* @return
*/
UserLike save(UserLike userLike);

/ **
* save or modify bulk
* @param List
* /
List <UserLike> saveAll (List <UserLike> List);


/ **
* Based on the thumbs of people like query id list of points (ie queries to the person who thumbs through)
* @param likedUserId be the point person like id
* @param the Pageable
* @return
* /
Page <UserLike> getLikedListByLikedUserId (String likedUserId, Pageable pageable) ;

/ **
* Like the query id list thumbs point person (ie, query the person who gave the thumbs up too)
* @param likedPostId
* @param the Pageable
* @return
* /
Page <UserLike> getLikedListByLikedPostId (String likedPostId, the Pageable the Pageable );

/ **
* the above mentioned id query whether there was point by point and the Chan Chan Chan who point record
* @param likedUserId
* @param likedPostId
* @return
* /
UserLike getByLikedUserIdAndLikedPostId (likedUserId String, String likedPostId);

/ **
* Redis in the dot data stored in the database Like
* /
void transLikedFromRedis2DB ();

/ **
* Like the number of data points is stored in the database Redis
* /
void transLikedCountFromRedis2DB ();

}
LikedServiceImpl implementation class

import com.solo.coderiver.user.dataobject.UserInfo;
import com.solo.coderiver.user.dataobject.UserLike;
import com.solo.coderiver.user.dto.LikedCountDTO;
import com.solo.coderiver.user.enums.LikedStatusEnum;
import com.solo.coderiver.user.repository.UserLikeRepository;
import com.solo.coderiver.user.service.LikedService;
import com.solo.coderiver.user.service.RedisService;
import com.solo.coderiver.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Slf4j
public class LikedServiceImpl implements LikedService {

@Autowired
UserLikeRepository likeRepository;

@Autowired
RedisService redisService;

@Autowired
UserService userService;

@Override
@Transactional
public UserLike save(UserLike userLike) {
return likeRepository.save(userLike);
}

@Override
@Transactional
public List<UserLike> saveAll(List<UserLike> list) {
return likeRepository.saveAll(list);
}

@Override
public Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable) {
return likeRepository.findByLikedUserIdAndStatus(likedUserId, LikedStatusEnum.LIKE.getCode(), pageable);
}

@Override
public Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable) {
return likeRepository.findByLikedPostIdAndStatus(likedPostId, LikedStatusEnum.LIKE.getCode(), pageable);
}

@Override
public UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId) {
return likeRepository.findByLikedUserIdAndLikedPostId(likedUserId, likedPostId);
}

@Override
@Transactional
public void transLikedFromRedis2DB() {
List<UserLike> list = redisService.getLikedDataFromRedis();
for (UserLike like : list) {
UserLike ul = getByLikedUserIdAndLikedPostId(like.getLikedUserId(), like.getLikedPostId());
if (ul == null){
//没有记录,直接存入
save(like);
}else{
//有记录,需要更新
ul.setStatus(like.getStatus());
save(ul);
}
}
}

@Override
@Transactional
public void transLikedCountFromRedis2DB () {
List <LikedCountDTO> = redisService.getLikedCountFromRedis List ();
for (LikedCountDTO DTO: List) {
the UserInfo = User userService.findById (dto.getId ());
the number of belonging // thumbs insignificant operation, without throwing an error exception
IF (User = null!) {
Integer likeNum user.getLikeNum = () + dto.getCount ();
user.setLikeNum (likeNum);
// number of points update Like
userService.updateInfo (user );
}
}
}
}
operations on these databases, mainly CRUD.

Fourth, the opening timing of the task persistence stored in the database

Quartz is very strong regular tasks, use it.

Quartz Use these steps:

1. Add dependence

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2.编写配置文件

package com.solo.coderiver.user.config;

import com.solo.coderiver.user.task.LikeTask;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {

private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";

@Bean
public JobDetail quartzDetail(){
return JobBuilder.newJob(LikeTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();
}

@Bean
public quartzTrigger the Trigger () {
SimpleScheduleBuilder scheduleBuilder SimpleScheduleBuilder.simpleSchedule = ()
// .withIntervalInSeconds (10) to set the time period in seconds //
.withIntervalInHours (2) // two hours to perform a
.repeatForever ();
return TriggerBuilder. newTrigger () forJob (quartzDetail ()).
.withIdentity (LIKE_TASK_IDENTITY)
.withSchedule (scheduleBuilder)
.build ();
}
}
3. written to perform tasks class inherits from QuartzJobBean

package com.solo.coderiver.user.task;

import com.solo.coderiver.user.service.LikedService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;

/ **
* Like the timing point of the task
* /
@ SLF4J
public class LikeTask the extends QuartzJobBean {

@Autowired
LikedService likedService;

private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {

log.info("LikeTask-------- {}", sdf.format(new Date()));

// The Redis Like in the point information database to synchronize
likedService.transLikedFromRedis2DB ();
likedService.transLikedCountFromRedis2DB ();
}
}
In the timing task called directly LikedService encapsulation method for data synchronization.

Guess you like

Origin www.cnblogs.com/1993zzd/p/11987531.html