业务代码中先处置惩罚业务末了存储数据

王柳  金牌会员 | 2024-10-29 11:34:10 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 886|帖子 886|积分 2658

背景说明:
在处置惩罚复杂业务的时候,特别是研发自测期间,经常会产生很多不必要的垃圾数据。
技能原理:
先将要存入数据库的数据放在缓存中,等所有业务代码实行完后,再同一生存;
代码如下:
  1. @Slf4j
  2. public class BaseService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements IService<T> {
  3.     /**
  4.      * 构建查询
  5.      * @param e
  6.      * @return
  7.      */
  8.     @SneakyThrows
  9.     public <E extends Object> EntityWrapper<E> wrapperTable(E e, String tableName, Boolean like) {
  10.         EntityWrapper<E> wrapper = new EntityWrapper<>();
  11.         for (String field: JSON.parseObject(JSON.toJSONString(e)).keySet()) {
  12.             Field ld = findField(e.getClass(), field);
  13.             if(ld == null || !checkField(ld)) continue;
  14.             String _s = columnName(ld);
  15.             String m =null;
  16.             if(_s.contains("_")){
  17.                  m = StrUtil.toCamelCase("get_"+_s);
  18.             }else {m=StrUtil.genGetter(_s);}
  19.             Object o = e.getClass().getMethod(m).invoke(e);
  20.             if(ObjectUtils.isEmpty(o)) continue;
  21.             if(!ObjectUtils.isEmpty(tableName)) {
  22.                 _s = tableName+"."+_s;
  23.             }
  24.             if(like) wrapper.like(_s,o.toString());
  25.             else wrapper.eq(_s , o);
  26.         }
  27.         return wrapper;
  28.     }
  29.     /**
  30.      * 构建查询
  31.      * @param e
  32.      * @return
  33.      */
  34.     @SneakyThrows
  35.     public <E extends Object> EntityWrapper<E> wrapper(E e, Boolean like) {
  36.         return wrapperTable(e,null,like);
  37.     }
  38.     /**
  39.      * 构建查询
  40.      * @param e
  41.      * @return
  42.      */
  43.     @SneakyThrows
  44.     public <E extends Object> EntityWrapper<E> wrapper(E e) {
  45.         return wrapperTable(e,null,false);
  46.     }
  47.     private boolean checkField(Field field) {
  48.         if(!field.isAnnotationPresent(TableId.class) && !field.isAnnotationPresent(TableField.class)) return false;
  49.         if(field.isAnnotationPresent(TableField.class) && !field.getAnnotation(TableField.class).exist()) return false;
  50.         return true;
  51.     }
  52.     private Field findField(Class c,String field) {
  53.         if(c == Object.class) return null;
  54.         try {
  55.             return c.getDeclaredField(field);
  56.         } catch (NoSuchFieldException e) {
  57.             return findField(c.getSuperclass(),field);
  58.         }
  59.     }
  60.     private String columnName(Field field) {
  61.         if(field.isAnnotationPresent(TableId.class) && ObjectUtils.isNotEmpty(field.getAnnotation(TableId.class).value())) return field.getAnnotation(TableId.class).value();
  62.         if(field.isAnnotationPresent(TableField.class) && field.getAnnotation(TableField.class).exist() && ObjectUtils.isNotEmpty(field.getAnnotation(TableField.class).value())) return field.getAnnotation(TableField.class).value();
  63.         return StrUtil.toUnderlineCase(field.getName());
  64.     }
  65.     @Transactional(rollbackFor = Exception.class)
  66.     @Override
  67.     public boolean insertOrUpdate(T entity){
  68.         if(entity instanceof TransacationalEntity) {
  69.             //截流所有 TransacationalEntity 下的新增
  70.             if(((TransacationalEntity) entity).getSqlStatus().equalsIgnoreCase("begin")) {
  71.                 return TransactionalUtils.add(this,((TransacationalEntity) entity));
  72.             } else if(((TransacationalEntity) entity).getSqlStatus().equalsIgnoreCase("commit")) {
  73.                 return TransactionalUtils.commit(((TransacationalEntity) entity).getSqlVersion());
  74.             } else {
  75.                 return super.insertOrUpdate(entity);
  76.             }
  77.         } else {
  78.             return super.insertOrUpdate(entity);
  79.         }
  80.     }
  81.     @SneakyThrows
  82.     @Transactional(rollbackFor = Exception.class)
  83.     @Override
  84.     public boolean insertOrUpdateBatch(List<T> entityList) {
  85.         try {
  86.             this.baseMapper.getClass().getMethod("insertOrUpdateBatch", List.class).invoke(this.baseMapper,entityList);
  87.         } catch (NoSuchMethodException e) {
  88.             log.warn("mapper类{},不存在方法{},替换为service执行",this.baseMapper.getClass(),"insertOrUpdateBatch");
  89.             super.insertOrUpdateBatch(entityList);
  90.         }
  91.         return true;
  92.     }
  93. }
复制代码
业务父类其他方法可以忽略,都是懒得写xml但是版本又不允许升级,偷懒写的sql条件辅助工具。
主要要关注以下两个方法:
第一个,用于截流原来的生存方法,将要生存的数据存入缓存中。
  1. @Transactional(rollbackFor = Exception.class)
  2.     @Override
  3.     public boolean insertOrUpdate(T entity){
  4.         if(entity instanceof TransacationalEntity) {
  5.             //截流所有 TransacationalEntity 下的新增
  6.             if(((TransacationalEntity) entity).getSqlStatus().equalsIgnoreCase("begin")) {
  7.                 return TransactionalUtils.add(this,((TransacationalEntity) entity));
  8.             } else if(((TransacationalEntity) entity).getSqlStatus().equalsIgnoreCase("commit")) {
  9.                 return TransactionalUtils.commit(((TransacationalEntity) entity).getSqlVersion());
  10.             } else {
  11.                 return super.insertOrUpdate(entity);
  12.             }
  13.         } else {
  14.             return super.insertOrUpdate(entity);
  15.         }
  16.     }
复制代码
第二个,用于末了同一处置惩罚生存,我这里偷懒了,使用了代码生成器,所以xml中已经有了 insertOrupdataBatch.
  1. @SneakyThrows
  2.     @Transactional(rollbackFor = Exception.class)
  3.     @Override
  4.     public boolean insertOrUpdateBatch(List<T> entityList) {
  5.         try {
  6.             this.baseMapper.getClass().getMethod("insertOrUpdateBatch", List.class).invoke(this.baseMapper,entityList);
  7.         } catch (NoSuchMethodException e) {
  8.             log.warn("mapper类{},不存在方法{},替换为service执行",this.baseMapper.getClass(),"insertOrUpdateBatch");
  9.             super.insertOrUpdateBatch(entityList);
  10.         }
  11.         return true;
复制代码
  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class TransacationalEntity {
  5.     /**
  6.      * begin null commit
  7.      */
  8.     @TableField(exist = false)
  9.     @ApiModelProperty(hidden = true)
  10.     private String sqlStatus;
  11.     /**
  12.      * begin null commit
  13.      */
  14.     @TableField(exist = false)
  15.     @ApiModelProperty(hidden = true)
  16.     private String sqlVersion;
  17. }
复制代码
Pojo父类
  1. public class TransactionalUtils {
  2.     static volatile ConcurrentHashMap<String, ConcurrentHashMap<BaseService, CopyOnWriteArrayList<Object>>> cMap = new ConcurrentHashMap<>();
  3.     static volatile ConcurrentHashMap<String,Long> tMap = new ConcurrentHashMap<>();
  4.      public static <E extends TransacationalEntity> boolean add(BaseService service, E e) {
  5.          long millis = System.currentTimeMillis();
  6.          synchronized(service.getClass()) {
  7.             ConcurrentHashMap<BaseService, CopyOnWriteArrayList<Object>> map = cMap
  8.                     .getOrDefault(e.getSqlVersion(), new ConcurrentHashMap<>());
  9.             CopyOnWriteArrayList<Object> list = map.getOrDefault(service, new CopyOnWriteArrayList<>());
  10.             list.add(e);
  11.             map.put(service, list);
  12.             cMap.put(e.getSqlVersion(), map);
  13.             tMap.put(e.getSqlVersion(),tMap.getOrDefault(e.getSqlVersion(), 0L)+System.currentTimeMillis()-millis) ;
  14.         }
  15.          return true;
  16.     }
  17.     @SneakyThrows
  18.     public static boolean commit(String key) {
  19.         long millis = System.currentTimeMillis();
  20.         int size = 0;
  21.         for (Map.Entry<BaseService, CopyOnWriteArrayList<Object>> entry : cMap.remove(key).entrySet()) {
  22.             entry.getKey().insertOrUpdateBatch(entry.getValue());
  23.             size+=entry.getValue().size();
  24.         }
  25.         System.out.println("批量业务入队总量" + size);
  26.         System.out.println("批量业务入队耗时" + tMap.remove(key));
  27.         System.out.println("批量业务提交耗时" + (System.currentTimeMillis()-millis));
  28.         return true;
  29.     }
  30. }
复制代码
核心工具类以下是调用示例:
  1. String tranId = IdUtil.simpleUUID();
  2.         Map<String, Object> userMap = new HashMap();
  3.         userMap.put("sqlStatus","begin");
  4.         userMap.put("sqlVersion", tranId);
  5.         propretyDye(beans,userMap);
  6.         insertOrUpdate(Arrays.asList(beans));
  7.         TransactionalUtils.commit(tranId);
复制代码
先给要截流的数据加上版本号和标识,其实只要一个版本号就可以了,sqlStatus这个字段懒得删除了。
版本号主要用来在缓存中分组,隔离其他业务提交。
附带一个参数处置惩罚的小工具,有时候要重复的一层层赋值,太懒了,所以写个工具,让机器本身给我处置惩罚所有数据的值,用法如上面的示例,没仔细检查,偶然会发生栈溢出,但是不影响,应该是项目的全局配置不够造成的:
  1. /**
  2.      * 属性染色
  3.      * 如果对象 o 包含 propreties 的key,则设置key对应的值
  4.      * 处理对象和对象中所有的子对象
  5.      * @param o
  6.      * @param propreties
  7.      * @return
  8.      */
  9.     @SneakyThrows
  10.     public static Object propretyDye(Object o, Map<String,Object> propreties) {
  11.         if(o instanceof Collection) for (Object object : (Collection<?>) o) {
  12.             propretyDye(object,propreties);
  13.         }
  14.         Class<?> aClass = o.getClass();
  15.         while (aClass instanceof Object) {
  16.             for (Field field : aClass.getDeclaredFields()) {
  17.                 field.setAccessible(true);
  18.                 if(propreties.containsKey(field.getName())) field.set(o,propreties.get(field.getName()));
  19.                 if(field.get(o) instanceof Collection) for (Object object : (Collection<?>) field.get(o)) {
  20.                     propretyDye(object,propreties);
  21.                 }
  22.                 if(field.get(o) instanceof Object && BeanUtil.isBean(field.get(o).getClass())) propretyDye(field.get(o),propreties);
  23.             }
  24.             aClass = aClass.getSuperclass();
  25.         }
  26.         return o;
  27.     }
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表