# DynamicCreateLatestRateTableTask.java

    package cloud.wconnect.rateshop.businesstask.rateshop;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.service.MailInternalService;
    import cloud.wconnect.rateshop.cons.rateshop.RateTypeEnum;
    import cloud.wconnect.rateshop.entity.rateshop.Iwc;
    import cloud.wconnect.rateshop.mapper.rateshop.IwcMapper;
    import cloud.wconnect.rateshop.mapper.rateshop.LatestRateMapper;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;

    import java.time.LocalDateTime;
    import java.time.Year;
    import java.time.format.DateTimeFormatter;
    import java.util.concurrent.TimeUnit;

    /**
     * 动态的创建latest_rate_yyyy表
     *
     * @author lichen
     * @date 2023/6/9
     */
    @Slf4j
    @Component
    @DS("rate_shop")
    public class DynamicCreateLatestRateTableTask {

        @Autowired
        private LatestRateMapper latestRateMapper;
        @Autowired
        private MailInternalService mailInternalService;
        @Autowired
        private RedisTemplate<String,Object> redisTemplate;
        @Autowired
        private IwcMapper iwcMapper;

        /**
         * 定时任务key
         */
        private static final String PREFIX_KEY_CREATE_TABLE = "wconnect:task:rate-shop:create-table:";
        private static final String PREFIX_KEY_SEND_EMAIL = "wconnect:task:rate-shop:table-not-exist-send-email:";

        /**
         * 动态创建表
         *
         * @return void
         * @author lichen
         * @date 2023/6/9
         */
        @Scheduled(cron = "${schedule.cron.create-latest-rate-table}", zone = "${default.timezone}")
        public void createTable() {
            String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern(BaseConstant.DATE_FORMAT_YYMMDD));
            if (!preventConcurrency(PREFIX_KEY_CREATE_TABLE + currentDate)) {
                return;
            }
            //下一年
            String nextYear = String.valueOf(Year.now().getValue() + 1);
            //获取表名
            for (String tableName : RateTypeEnum.getTableNames(nextYear)) {
                //表不存在时
                if(latestRateMapper.isTableExist(tableName) == 0){
                    //创建表
                    latestRateMapper.createLatestRateTable(tableName);
                }
            }

            //检查表是否存在
            int tableExistByIwc = iwcMapper.isTableExist(Iwc.TABLE_NAME_PREFIX + nextYear);
            if(tableExistByIwc == 0){
                //表不存在时，创建表
                iwcMapper.createTable(Iwc.TABLE_NAME_PREFIX + nextYear);
            }
        }

        /**
         * 检测表是否创建成功，不成功则发邮件
         *
         * @return void
         * @author lichen
         * @date 2023/6/9
         */
        @Scheduled(cron = "${schedule.cron.check-latest-rate-table}", zone = "${default.timezone}")
        public void checkTableIsExist(){
            String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern(BaseConstant.DATE_FORMAT_YYMMDD));
            if (!preventConcurrency(PREFIX_KEY_SEND_EMAIL + currentDate)) {
                return;
            }
            //下一年
            String nextYear = String.valueOf(Year.now().getValue() + 1);
            //获取表名
            for (String tableName : RateTypeEnum.getTableNames(nextYear)) {
                //表不存在时，发送alertEmail
                if(latestRateMapper.isTableExist(tableName) == 0){
                    String content = "The table:[" + tableName +"] was not created on the 20th";
                    mailInternalService.sendAlertEmail("Create LatestRateTable Error",content);
                }
            }

            //检查表是否存在
            int tableExistByIwc = iwcMapper.isTableExist(Iwc.TABLE_NAME_PREFIX + nextYear);
            if(tableExistByIwc == 0){
                //表不存在时，发送邮件
                String content = "The table:[" + Iwc.TABLE_NAME_PREFIX + nextYear +"] was not created";
                mailInternalService.sendAlertEmail("Create Iwc Table Error",content);
            }
        }

        /**
         * 检测定时任务是否并发执行
         *
         * @param key 缓存key
         * @return java.lang.Boolean
         * @author lichen
         * @date 2023/9/29
         */
        private Boolean preventConcurrency(String key) {
            return redisTemplate.opsForValue().setIfAbsent(key, 0, 1, TimeUnit.DAYS);
        }
    }