Browse Source

提交订单缓存模块--延时双删策略,尽量保证数据最终一致性

cangku
Houpn 3 years ago
parent
commit
7d8150044f
  1. 4
      hiver-admin/src/main/resources/application.yml
  2. 13
      hiver-core/src/main/java/cc/hiver/core/common/annotation/ClearAndReloadCache.java
  3. 77
      hiver-core/src/main/java/cc/hiver/core/common/aop/ClearAndReloadCacheAspect.java
  4. 10
      hiver-core/src/main/java/cc/hiver/core/config/cache/RedisCacheConfig.java
  5. 11
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/OrderController.java
  6. 12
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/handler/OrderXdHandler.java

4
hiver-admin/src/main/resources/application.yml

@ -80,10 +80,6 @@ spring:
max-wait: -1
max-idle: 8
min-idle: 0
#Canal服务用于数据同步
canal:
server: 154.8.162.157:11111
destination: example
# Elasticsearch
data:
elasticsearch:

13
hiver-core/src/main/java/cc/hiver/core/common/annotation/ClearAndReloadCache.java

@ -0,0 +1,13 @@
package cc.hiver.core.common.annotation;
import java.lang.annotation.*;
/**
*延时双删
**/
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.METHOD)
public @interface ClearAndReloadCache {
String name() default "";
}

77
hiver-core/src/main/java/cc/hiver/core/common/aop/ClearAndReloadCacheAspect.java

@ -0,0 +1,77 @@
package cc.hiver.core.common.aop;
import cc.hiver.core.common.annotation.ClearAndReloadCache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Set;
@Aspect
@Component
public class ClearAndReloadCacheAspect {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 切入点
*切入点,基于注解实现的切入点 加上该注解的都是Aop切面的切入点
*
*/
@Pointcut("@annotation(cc.hiver.core.common.annotation.ClearAndReloadCache)")
public void pointCut(){
}
/**
* 环绕通知
* 环绕通知非常强大可以决定目标方法是否执行什么时候执行执行时是否需要替换方法参数执行完毕是否需要替换返回值
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
* @param proceedingJoinPoint
*/
@Around("pointCut()")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("----------- 环绕通知 -----------");
System.out.println("环绕通知的目标方法名:" + proceedingJoinPoint.getSignature().getName());
Signature signature1 = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature)signature1;
Method targetMethod = methodSignature.getMethod();//方法对象
ClearAndReloadCache annotation = targetMethod.getAnnotation(ClearAndReloadCache.class);//反射得到自定义注解的方法对象
String name = annotation.name();//获取自定义注解的方法对象的参数即name
Set<String> keys = stringRedisTemplate.keys("*" + name + "*");//模糊定义key
stringRedisTemplate.delete(keys);//模糊删除redis的key值
//执行加入双删注解的改动数据库的业务 即controller中的方法业务
Object proceed = null;
try {
proceed = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//开一个线程 延迟1秒(此处是1秒举例,可以改成自己的业务)
// 在线程中延迟删除 同时将业务代码的结果返回 这样不影响业务代码的执行
new Thread(() -> {
try {
Thread.sleep(1000);
Set<String> keys1 = stringRedisTemplate.keys("*" + name + "*");//模糊删除
stringRedisTemplate.delete(keys1);
System.out.println("-----------1秒钟后,在线程中延迟删除完毕 -----------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
return proceed;//返回业务代码的值
}
}

10
hiver-core/src/main/java/cc/hiver/core/config/cache/RedisCacheConfig.java

@ -41,7 +41,7 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
RedisConnectionFactory factory;
@Override
/*@Override
public CacheResolver cacheResolver() {
// 通过Guava实现的自定义堆内存缓存管理器
CacheManager caffeineCacheManager = new CaffeineCacheManager();
@ -52,11 +52,11 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
// 堆内存缓存读取不到该key时再读取redis缓存
list.add(redisCacheManager);
return new CustomCacheResolver(list);
}
}*/
@Bean
public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory){
//@Bean
/*public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory){
//初始化一个redis模板
RedisTemplate<String, Serializable> template = new RedisTemplate<>();
// key采用String的序列化方式
@ -69,7 +69,7 @@ public class RedisCacheConfig extends CachingConfigurerSupport {
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}*/
/**
* 自定义序列化方式

11
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/OrderController.java

@ -1,6 +1,7 @@
package cc.hiver.base.controller.manage;
import cc.hiver.base.async.AddMessage;
import cc.hiver.core.common.annotation.ClearAndReloadCache;
import cc.hiver.core.common.constant.CommonConstant;
import cc.hiver.core.common.constant.UserConstant;
import cc.hiver.core.common.redis.RedisTemplateHelper;
@ -18,9 +19,11 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.annotations.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
@ -49,7 +52,7 @@ import java.util.stream.Collectors;
@CacheConfig(cacheNames = "orderxd")
@Transactional
public class OrderController {
public static final String ORDER = "orderxd::";
public static final String ORDER = "ORDER::";
@Autowired
private OrderService orderService;
@ -72,6 +75,7 @@ public class OrderController {
*/
@RequestMapping(value = "/getByCondition", method = RequestMethod.GET)
@ApiOperation(value = "多条件分页获取订单列表")
@Cacheable(cacheNames = "get method")
public Result<Page<OrderXd>> getByCondition(OrderXd order,
SearchVo searchVo,
PageVo pageVo) {
@ -95,7 +99,7 @@ public class OrderController {
public Result add(@Valid OrderXd u,
@RequestParam(required = false) String[] roleIds) {
OrderXd order = orderService.save(u);
orderService.save(u);
// 发送创建账号消息
//addMessage.addSendMessage(user.getId());
@ -128,6 +132,7 @@ public class OrderController {
*/
@RequestMapping(value = "/rush/order/{orderId}", method = RequestMethod.POST)
@ApiOperation(value = "抢单接口", notes = "需要通过下单编号获取订单信息后进行绑定")
@ClearAndReloadCache(name = ORDER)
public Result rush(OrderXd u,
@RequestParam(required = false) String[] roleIds) {
@ -145,6 +150,7 @@ public class OrderController {
*/
@RequestMapping(value = "/unbind/order/{orderId}", method = RequestMethod.POST)
@ApiOperation(value = "解绑订单接口", notes = "需要通过下单编号获取订单信息后进行解绑")
@ClearAndReloadCache(name = ORDER)
public Result revoke(OrderXd u,
@ApiParam("订单唯一id标识") @PathVariable String orderId) {
@ -152,6 +158,7 @@ public class OrderController {
o.setOrderByWorker("");
o.setOrderByWorkertime(null);
o.setWorker(null);
orderService.update(o);

12
hiver-modules/hiver-base/src/main/java/cc/hiver/base/handler/OrderXdHandler.java

@ -13,13 +13,13 @@ import top.javatool.canal.client.handler.EntryHandler;
* @Description
* @date 2022/9/25
*/
@CanalTable("bs_ecif")
@Component
@AllArgsConstructor
@Slf4j
//@CanalTable("t_order")
//@Component
//@AllArgsConstructor
//@Slf4j
public class OrderXdHandler implements EntryHandler<OrderXd> {
private final RedisTemplate<Object,Object> redisTemplate;
/*//private final RedisTemplate<Object,Object> redisTemplate;
@Override
public void insert(OrderXd orderXd) {
@ -37,5 +37,5 @@ public class OrderXdHandler implements EntryHandler<OrderXd> {
public void delete(OrderXd orderXd) {
log.info("[删除]"+orderXd);
redisTemplate.delete("ORDER:"+orderXd.getOrderId());
}
}*/
}

Loading…
Cancel
Save