SpringBoot如何統(tǒng)一清理數(shù)據(jù)
業(yè)務(wù)背景:
一般時(shí)序數(shù)據(jù)會(huì)有保存數(shù)據(jù)周期,例如三個(gè)月或者是半年之久,一般方案是定時(shí)任務(wù)調(diào)用dao層刪除數(shù)據(jù),不方便統(tǒng)一管理,擴(kuò)展性也不夠好,這里通過(guò)并發(fā)流線程池實(shí)現(xiàn)并行執(zhí)行刪除邏輯。
一、接口定義
package com.boot.skywalk.task; /** * 通用數(shù)據(jù)清理任務(wù)接口 */ @FunctionalInterface public interface ICleanData { /** * 清理數(shù)據(jù) */ void cleanData(); }
二、業(yè)務(wù)層模擬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"); } }
三、清理任務(wù)
@Slf4j @Component public class CleanDataTask { /** * 并發(fā)流定時(shí)任務(wù)清理過(guò)期數(shù)據(jù),集群部署時(shí)候,分布式任務(wù)只在一個(gè)節(jié)點(diǎn)運(yùn)行即可,XXL-JOB和Quartz中 */ public void clean(){ // 獲取所有需要實(shí)現(xiàn)業(yè)務(wù)清理數(shù)據(jù)的Bean List<ICleanData> dataList =CommonBeanUtils.getBeanList(ICleanData.class); Instant start=Instant.now(); log.info("start clean data"); // 并發(fā)流同時(shí)執(zhí)行業(yè)務(wù)層數(shù)據(jù)清理任務(wù) dataList.parallelStream().forEach(cleanable->{ // 具體異常在各自實(shí)現(xiàn)邏輯中單獨(dú)捕獲 cleanable.cleanData(); }); Instant end=Instant.now(); long costTime = Duration.between(start, end).getSeconds(); log.info("finish clean data,cost time={}", costTime); } }
四、測(cè)試運(yùn)行
任務(wù)并行執(zhí)行刪除邏輯耗時(shí)2秒鐘,并發(fā)流線程池ForkJoinPool.業(yè)務(wù)開發(fā)只需繼承數(shù)據(jù)清理接口實(shí)現(xiàn)各自自己的數(shù)據(jù)清理邏輯即可,這里可以采用自定義線程池+CountDownLatch來(lái)實(shí)現(xiàn),業(yè)務(wù)線程邏輯更加好控制.
【附錄SpringBoot項(xiàng)目時(shí)間處理】
建表SQL如下:新增和修改時(shí)候自動(dòng)更新時(shí)間
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 '創(chuàng)建時(shí)間', update_time datetime not null default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新時(shí)間' ) engine = Innodb default charset = utf8mb4 comment '用戶信息表';
新增修改都是自動(dòng)更新時(shí)間.
基于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; /** * 查詢?nèi)苛斜? * @return */ @RequestMapping("/boot/users") public List<UserInfo> getUserInfoList(){ return userInfoService.list(); } }
查詢列表返回?cái)?shù)據(jù).
時(shí)間處理策略:
①、前段處理展示.
②、SimpleDateFormat格式化或者是DateTimeFormatter格式化來(lái)增加字段處理,大型項(xiàng)目有專門的TimeUtil來(lái)轉(zhuǎn)換各種時(shí)間,項(xiàng)目中的時(shí)間是point來(lái)存儲(chǔ)時(shí)間戳然后進(jìn)行轉(zhuǎn)化.
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// 輸出結(jié)果時(shí)隱藏此字段 private Date createTime; @TableField("update_time") @JsonIgnore// 輸出結(jié)果時(shí)隱藏此字段 private Date updateTime; // 時(shí)間格式化后的字段,數(shù)據(jù)庫(kù)不存在的字段 @TableField(exist = false) private String ctime; // 時(shí)間格式化后的字段,數(shù)據(jù)庫(kù)不存在的字段 @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 { // 定義時(shí)間格式化對(duì)象和定義格式化樣式 private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Autowired private UserInfoService userInfoService; /** * 查詢?nèi)苛斜? * @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添加對(duì)應(yīng)注解即可
@TableField("update_time") //@JsonIgnore// 輸出結(jié)果時(shí)隱藏此字段 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") private Date updateTime;
④、或者在全局配置文件中進(jìn)行配置
【附錄定時(shí)任務(wù)創(chuàng)建分表】也可以基于并發(fā)流創(chuàng)建然后配置完整的告警管理,實(shí)現(xiàn)統(tǒng)一接口然后并發(fā)流創(chuàng)建.
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); }
控制臺(tái)執(zhí)行日志:
information_schema.TABLE表中查看
【驗(yàn)證數(shù)據(jù)庫(kù)字符串處理時(shí)間】
數(shù)據(jù)庫(kù)建表字段 為timestamp/datatime,前段時(shí)間為字符串處理
{ "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 );
接口層時(shí)間獲取json數(shù)據(jù),@RequestBody接收,比較簡(jiǎn)單.
@PostMapping("/insert/resultVo") public String saveResultVo(@RequestBody CustomResultVo customResultVo){ try { resultMapper.save(customResultVo); } catch (Exception e) { log.info("save error",e); } return "Success"; }
這里測(cè)試使用jdbcType的DATE類型
<!--數(shù)據(jù) --> <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接收前端時(shí)間json字符串參數(shù)
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; /** * 設(shè)置時(shí)間格式, */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") @JsonProperty("create_time") private Date createTime; }
MyBatis的JdbcType枚舉,這里轉(zhuǎn)換使用TimeStamp
數(shù)據(jù)庫(kù)建表語(yǔ)句
查詢數(shù)據(jù)庫(kù),發(fā)現(xiàn)只有年月日
XML中修改為TimeStamp
再次查詢數(shù)據(jù),保存正常。
MyBatis處理MySQL字段類型date與datetime
五、總結(jié)歸納
不僅僅是數(shù)據(jù)清理,也包括一些需要并行的邏輯可以采用并發(fā)流的方式來(lái)執(zhí)行,注意是IO密集型還是CPU密集型選擇對(duì)應(yīng)的框架和線程池即可.
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java.lang.Long cannot be cast to ja
本文主要介紹了java.lang.Long cannot be cast to java.lang.Integer數(shù)據(jù)類型轉(zhuǎn)換異常解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼
這篇文章主要介紹了application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn)
本文主要介紹了SpringBoot對(duì)接小程序微信支付的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧<BR>2023-09-091秒實(shí)現(xiàn)Springboot 圖片添加水印功能
這篇文章主要介紹了1秒實(shí)現(xiàn)Springboot 圖片添加水印功能,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12SpringCloud中使用Sentinel實(shí)現(xiàn)限流的實(shí)戰(zhàn)
限流在很多地方都可以使用的到,本篇博客將介紹如何使用SpringCloud中使用Sentinel實(shí)現(xiàn)限流,從而達(dá)到服務(wù)降級(jí)的目的,感興趣的可以了解一下2022-01-01Java虛擬機(jī)JVM性能優(yōu)化(一):JVM知識(shí)總結(jié)
這篇文章主要介紹了Java虛擬機(jī)JVM性能優(yōu)化(一):JVM知識(shí)總結(jié),本文是系列文章的第一篇,后續(xù)篇章請(qǐng)繼續(xù)關(guān)注腳本之家,需要的朋友可以參考下2014-09-09Java實(shí)現(xiàn)一鍵獲取Mysql所有表字段設(shè)計(jì)和建表語(yǔ)句的工具類
這篇文章主要為大家詳細(xì)介紹了如何利用Java編寫一個(gè)工具類,可以實(shí)現(xiàn)一鍵獲取Mysql所有表字段設(shè)計(jì)和建表語(yǔ)句,感興趣的小伙伴可以了解一下2023-05-05