java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot统一清理数据

SpringBoot如何统一清理数据

作者:大道之简

这篇文章主要介绍了SpringBoot如何统一清理数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

业务背景:

一般时序数据会有保存数据周期,例如三个月或者是半年之久,一般方案是定时任务调用dao层删除数据,不方便统一管理,扩展性也不够好,这里通过并发流线程池实现并行执行删除逻辑。

一、接口定义

package com.boot.skywalk.task;
/**
 * 通用数据清理任务接口
 */
@FunctionalInterface
public interface ICleanData {
    /**
     * 清理数据
     */
    void cleanData();
}

二、业务层模拟Dao层删除逻辑

@Slf4j
@Component
public class ConfigService implements ICleanData {
    @Autowired
    private ConfigDao configDao;
 
    @Override
    public void cleanData() {
        configDao.deleteConfigData(); 
        log.info("ConfigService Clean Success");
    }
}
@Slf4j
@Component
public class StatService implements ICleanData {
    @Autowired
    private StatDao statDao;
 
    @Override
    public void cleanData() {
        statDao.deleteStatData();    
        log.info("StatService Clean Success");
    }
}

三、清理任务

@Slf4j
@Component
public class CleanDataTask {
    /**
     * 并发流定时任务清理过期数据,集群部署时候,分布式任务只在一个节点运行即可,XXL-JOB和Quartz中
     */
    public void clean(){
        // 获取所有需要实现业务清理数据的Bean
        List<ICleanData> dataList =CommonBeanUtils.getBeanList(ICleanData.class);
        Instant start=Instant.now();
        log.info("start clean data");
        // 并发流同时执行业务层数据清理任务
        dataList.parallelStream().forEach(cleanable->{
            // 具体异常在各自实现逻辑中单独捕获
           cleanable.cleanData();
        });
        Instant end=Instant.now();
        long costTime = Duration.between(start, end).getSeconds();
        log.info("finish clean data,cost time={}", costTime);
    }
}

四、测试运行

任务并行执行删除逻辑耗时2秒钟,并发流线程池ForkJoinPool.业务开发只需继承数据清理接口实现各自自己的数据清理逻辑即可,这里可以采用自定义线程池+CountDownLatch来实现,业务线程逻辑更加好控制.

【附录SpringBoot项目时间处理】

建表SQL如下:新增和修改时候自动更新时间

create table user_info (
	id int primary key auto_increment comment '主键ID',
    user_name varchar(50) not null comment '用户名称',
    create_time datetime not null default CURRENT_TIMESTAMP comment '创建时间',
    update_time datetime not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间'
    ) engine = Innodb default charset = utf8mb4 comment '用户信息表';

新增修改都是自动更新时间. 

基于MyBatis-Plus的方式的三层

Mapper层:

package com.boot.skywalk.mapper;
 
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.boot.skywalk.entity.UserInfo;
 
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

Xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.boot.skywalk.mapper.UserInfoMapper">
 
</mapper>

service

package com.boot.skywalk.service;
 
import com.baomidou.mybatisplus.extension.service.IService;
import com.boot.skywalk.entity.UserInfo;
 
public interface UserInfoService extends IService<UserInfo> {
}

impl

package com.boot.skywalk.service.impl;
 
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.boot.skywalk.entity.UserInfo;
import com.boot.skywalk.mapper.UserInfoMapper;
import com.boot.skywalk.service.UserInfoService;
import org.springframework.stereotype.Service;
 
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
}

controller

package com.boot.skywalk.controller;
 
import com.boot.skywalk.entity.UserInfo;
import com.boot.skywalk.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.List;
 
@Slf4j
@RestController
public class UserInfoController {
 
    @Autowired
    private UserInfoService userInfoService;
 
    /**
     * 查询全部列表
     * @return
     */
    @RequestMapping("/boot/users")
    public List<UserInfo> getUserInfoList(){
        return userInfoService.list();
    }
}

查询列表返回数据.

时间处理策略:

、前段处理展示.

、SimpleDateFormat格式化或者是DateTimeFormatter格式化来增加字段处理,大型项目有专门的TimeUtil来转换各种时间,项目中的时间是point来存储时间戳然后进行转化.

package com.boot.skywalk.entity;
 
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
 
import javax.persistence.Table;
import java.util.Date;
 
@Data
@Table(name="user_info")
public class UserInfo {
    @TableId(type = IdType.AUTO)
    private Integer id;
 
    @TableField("user_name")
    private String userName;
 
    @TableField("create_time")
    @JsonIgnore// 输出结果时隐藏此字段
    private Date createTime;
 
    @TableField("update_time")
    @JsonIgnore// 输出结果时隐藏此字段
    private Date updateTime;
 
    // 时间格式化后的字段,数据库不存在的字段
    @TableField(exist = false)
    private String ctime;
 
    // 时间格式化后的字段,数据库不存在的字段
    @TableField(exist = false)
    private String utime;
}

controller修改.

package com.boot.skywalk.controller;
 
import com.boot.skywalk.entity.UserInfo;
import com.boot.skywalk.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.text.SimpleDateFormat;
import java.util.List;
 
@Slf4j
@RestController
public class UserInfoController {
 
    // 定义时间格式化对象和定义格式化样式
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
    @Autowired
    private UserInfoService userInfoService;
 
    /**
     * 查询全部列表
     * @return
     */
    @RequestMapping("/boot/users")
    public List<UserInfo> getUserInfoList(){
        List<UserInfo> list = userInfoService.list();
        list.forEach(user->{
           user.setCtime(dateFormat.format(user.getCreateTime()));
           user.setUtime(dateFormat.format(user.getUpdateTime()));
        });
        return list;
    }
}

、使用@JsonFormat添加对应注解即可

    @TableField("update_time")
    //@JsonIgnore// 输出结果时隐藏此字段
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date updateTime;

、或者在全局配置文件中进行配置

附录定时任务创建分表】也可以基于并发流创建然后配置完整的告警管理,实现统一接口然后并发流创建.

Xml

<mapper namespace="com.boot.skywalk.mapper.SupportMapper">
    <update id="createTable" parameterType="String">
        create table ${tableName}  (
            id int(11) auto_increment primary key,
            user_name varchar(20) not null,
            user_password varchar(20) not null
        );
    </update>
</mapper>
package com.boot.skywalk.mapper;
 
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
 
@Repository
public interface SupportMapper {
    /**
     * createTable
     * @param tableName
     * @return int
     */
    int createTable(@Param("tableName") String tableName);
}

控制台执行日志: 

information_schema.TABLE表中查看

验证数据库字符串处理时间

数据库建表字段 为timestamp/datatime,前段时间为字符串处理

{
  "name": "Dubbo",
  "address": "GuangZhou",
  "create_time": "2023-01-14 20:19:24"
}
create table result(
  id int(11) auto_increment primary key,
  `name` varchar(10) not null,
  address varchar(30) not null,
  create_time timestamp
);

接口层时间获取json数据,@RequestBody接收,比较简单.

    @PostMapping("/insert/resultVo")
    public String saveResultVo(@RequestBody CustomResultVo customResultVo){
        try {
            resultMapper.save(customResultVo);
        } catch (Exception e) {
            log.info("save error",e);
        }
        return "Success";
    }

这里测试使用jdbcType的DATE类型 

    <!--数据 -->
    <insert id="save" useGeneratedKeys="true" keyProperty="id" parameterType="com.boot.skywalk.vo.CustomResultVo">
        insert into result(`name`,`address`,`create_time`) values(#{name,jdbcType=VARCHAR},#{address,jdbcType=VARCHAR},#{createTime,jdbcType=DATE})
    </insert>

使用Java的Date接收前端时间json字符串参数 

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
import java.util.Date;
 
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomResultVo {
    private int id;
    private String name;
    private String address;
    /**
     * 设置时间格式,
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    @JsonProperty("create_time")
    private Date createTime;
}

 MyBatis的JdbcType枚举,这里转换使用TimeStamp

数据库建表语句

查询数据库,发现只有年月日

XML中修改为TimeStamp

再次查询数据,保存正常。

MyBatis处理MySQL字段类型date与datetime

五、总结归纳 

不仅仅是数据清理,也包括一些需要并行的逻辑可以采用并发流的方式来执行,注意是IO密集型还是CPU密集型选择对应的框架和线程池即可.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文