SpringBoot自定义动态定时任务(三十五)

news2025/1/16 11:13:26

二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。

上一章简单介绍了SpringBoot整合Quartz实现动态定时任务(三十四) ,如果没有看过,请观看上一章

通过 Quartz 实现了动态定时任务,还需要引入 Quartz 组件,

能不能不引入组件,我们自己创建一个简单的动态定时任务呢?

本章节参考了文章: SpringBoot动态定时任务(完整版)

在这个大佬的基础上,进行了扩充。

SpringBoot 自定义动态定时任务

使用到了 MybatisPlus 组件信息, 不使用 Quartz 组件。

 		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
		<!--引入MySql的驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--引入springboot与mybatis-plus整合的依赖。 去掉mybatis的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <!-- 引入pagehelper分页插件  注意版本号要与 mybatis-plus 进行匹配到 -->
        <!--分页-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
            <exclusions>
                <exclusion>
                    <artifactId>mybatis</artifactId>
                    <groupId>org.mybatis</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>mybatis-spring</artifactId>
                    <groupId>org.mybatis</groupId>
                </exclusion>
                <exclusion>
                    <groupId>com.github.jsqlparser</groupId>
                    <artifactId>jsqlparser</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- json 工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

定义实体,创建表 ScheduleSetting 用于维护动态任务信息

/**
 * 任务表
 *
 * @author yuejianli
 * @date 2023-01-05
 */
@Data
@TableName("schedule_setting")
public class ScheduleSetting {
    /**
     * 任务ID
     */
    @TableId(value = "id",type= IdType.AUTO)
    private Integer id;
    /**
     * bean名称
     */
    @TableField("bean_name")
    private String beanName;
    /**
     * 方法名称
     */
    @TableField("method_name")
    private String methodName;
    /**
     * 方法参数
     */
    @TableField("method_params")
    private String methodParams;
    /**
     * cron表达式
     */
    @TableField("cron_expression")
    private String cronExpression;
    /**
     * 状态(1正常 0暂停)
     */
    @TableField("job_status")
    private Integer jobStatus;
    /**
     * 备注
     */
    @TableField("remark")
    private String remark;
    /**
     * 创建时间
     */
    @TableField("create_time")
    private Date createTime;
    /**
     * 更新时间
     */
    @TableField("update_time")
    private Date updateTime;
}

对应的 SQL 语句是:

drop table if exists `schedule_setting`;
CREATE TABLE `schedule_setting` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '任务ID',
`bean_name` varchar(255) DEFAULT NULL COMMENT 'bean名称',
`method_name` varchar(255) DEFAULT NULL COMMENT '方法名称',
`method_params` varchar(255) DEFAULT NULL COMMENT '方法参数',
`cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`job_status` int DEFAULT NULL COMMENT '状态(1正常 0暂停)',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建 ScheduleSetting 对应的 Mapper 和 Service

这个就不讲了哈, 详情可以看 老蝴蝶之前写的 MybatisPlus 章节: SpringBoot整合MyBatisPlus(十四)

ScheduleSettingMapper

@Mapper
public interface ScheduleSettingMapper extends BaseMapper<ScheduleSetting> {

}

ScheduleSettingService

public interface ScheduleSettingService extends IService<ScheduleSetting> {
    /**
      查询所有运行中的任务
     */
    List<ScheduleSetting> findAllRunJob();
}
@Service
@Slf4j
public class ScheduleSettingServiceImpl extends ServiceImpl<ScheduleSettingMapper, ScheduleSetting>
    implements ScheduleSettingService{


    @Override
    public List<ScheduleSetting> findAllRunJob() {
        return this.lambdaQuery()
                .eq(ScheduleSetting::getJobStatus,1)
                .list();
    }
}

TaskScheduler 线程池配置 SchedulingConfig

@Configuration
public class SchedulingConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 定时任务执行线程池核心线程数
        taskScheduler.setPoolSize(6);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}

线程任务处理 ScheduledTask

ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。

/**
 * 调度任务
 *
 * @author yuejianli
 * @date 2023-01-05
 */

public final class ScheduledTask {

    volatile ScheduledFuture<?> future;
    /**
     * 取消定时任务
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}

线程池调用执行任务 SchedulingRunnable

被定时任务线程池调用,用来执行指定bean里面的方法。

@Slf4j
public class SchedulingRunnable implements Runnable {
    
    private String beanName;

    private String methodName;

    private String params;

    public SchedulingRunnable(String beanName, String methodName) {
        this(beanName, methodName, null);
    }

    public SchedulingRunnable(String beanName, String methodName, String params) {
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        log.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
        long startTime = System.currentTimeMillis();

        try {
            Object target = SpringContextUtils.getBean(beanName);

            Method method = null;
            if (StringUtils.hasText(params)) {
                method = target.getClass().getDeclaredMethod(methodName, String.class);
            } else {
                method = target.getClass().getDeclaredMethod(methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if (StringUtils.hasText(params)) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception ex) {
            log.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
        }

        long times = System.currentTimeMillis() - startTime;
        log.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒", beanName, methodName, params, times);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        SchedulingRunnable that = (SchedulingRunnable) o;
        if (params == null) {
            return beanName.equals(that.beanName) &&
                    methodName.equals(that.methodName) &&
                    that.params == null;
        }

        return beanName.equals(that.beanName) &&
                methodName.equals(that.methodName) &&
                params.equals(that.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }

        return Objects.hash(beanName, methodName, params);
    }
}

注意,获取类时,使用的是

Object target = SpringContextUtils.getBean(beanName);

获取的是 Spring 组件名, 并不是全限定名称。

Cron定时任务注册类 CronTaskRegistrar

@Component
public class CronTaskRegistrar implements DisposableBean {

    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);

    @Resource
    private TaskScheduler taskScheduler;

    public void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (this.scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }

            this.scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }

    public void removeCronTask(Runnable task) {
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null) {
            scheduledTask.cancel();
        }
    }

    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return scheduledTask;
    }


    @Override
    public void destroy() {
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }

        this.scheduledTasks.clear();
    }
}

全局获取 Bean 的工具类 SpringContextUtils

@Component
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }

    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    public static Class<? extends Object> getType(String name) {
        return applicationContext.getType(name);
    }
}

服务启动时,对任务处理 SysJobRunner

/**
 * 服务启动时处理任务
 *
 * @author yuejianli
 * @date 2023-01-05
 */
@Slf4j
@Component
public class SysJobRunner implements CommandLineRunner {

    @Resource
    private CronTaskRegistrar cronTaskRegistrar;

    @Resource
    private ScheduleSettingService scheduleSettingService;
    @Override
    public void run(String... args) {
        // 初始加载数据库里状态为正常的定时任务
        List<ScheduleSetting> jobList = scheduleSettingService.findAllRunJob();
        if (CollectionUtils.isNotEmpty(jobList)) {
            for (ScheduleSetting job : jobList) {
                SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(), job.getMethodName(), job.getMethodParams());
                cronTaskRegistrar.addCronTask(task, job.getCronExpression());
            }
            log.info("定时任务已加载完毕...");
        }
    }
}

定时任务创建

创建两个定时任务, 一个无参数,一个有参数。

public interface BaseTask {
    /**
     * 执行任务
     * @param param 参数
     */
    void execute(String param);
}
@Slf4j
@Component("myTask1")
public class MyTask1  implements BaseTask{

    @Resource
    private UserService userService;

    @Override
    public void execute(String param)  {
            log.info("   空参数任务 :" );
            userService.addUser(null);
    }
}
@Slf4j
@Component("myTask2")
public class MyTask2 implements BaseTask{

    @Resource
    private UserService userService;

    @Override
    public void execute(String param) {
        log.info("   有参数任务 :" + param);
        if (ObjectUtils.isEmpty(param)) {
            userService.addUser(null);
            return ;
        }
        Map<String,String> jobDataMap = JSON.parseObject(param,Map.class);
        User user = new User();
        user.setName(jobDataMap.get("name"));
        user.setAge(Integer.parseInt(jobDataMap.get("age")));
        user.setSex(jobDataMap.get("sex"));
        user.setDescription(jobDataMap.get("description"));
        userService.addUser(user);
    }
}

对定时任务和表进行业务整合

/**
 * 任务封装处理
 *
 * @author Yue Jianli
 * @date 2023-01-05
 */
public interface JobService {
    /**
        查询所有运行的任务
     */
    List<ScheduleSetting> findAllRunJob();
    /**
     * 创建定时任务
     * @param scheduleSetting 任务参数对象
     */
    boolean createJob(ScheduleSetting scheduleSetting);
    /**
     * 更新定时任务
     * @param scheduleSetting 任务参数对象
     */
    boolean updateJob(ScheduleSetting scheduleSetting);
    /**
     * 删除任务
     * @param id 任务id
     */
    boolean deleteJob(Integer id);
    /**
     * 暂停任务
     * @param id 任务id
     */
    boolean pauseJob(Integer id);
    /**
     * 重新开始任务
     * @param id 任务id
     */
    boolean resumeJob(Integer id);
}
@Service
@Slf4j
public class JobServiceImpl implements JobService{

    @Resource
    private CronTaskRegistrar cronTaskRegistrar;

    @Resource
    private ScheduleSettingService scheduleSettingService;

    @Override
    public List<ScheduleSetting> findAllRunJob() {
        return scheduleSettingService.findAllRunJob();
    }

    @Override
    public boolean createJob(ScheduleSetting scheduleSetting) {


        scheduleSetting.setCreateTime(new Date());
        scheduleSetting.setUpdateTime(new Date());

        boolean insert = scheduleSettingService.save(scheduleSetting);
        if (!insert) {
            return false;
        }
        // 添加成功,并且状态是1,直接放入任务器
        if (scheduleSetting.getJobStatus().equals(1)) {
            SchedulingRunnable task = new SchedulingRunnable(scheduleSetting.getBeanName(), scheduleSetting.getMethodName(), scheduleSetting.getMethodParams());
            cronTaskRegistrar.addCronTask(task, scheduleSetting.getCronExpression());
        }
        return true;
    }

    @Override
    public boolean updateJob(ScheduleSetting scheduleSetting) {

        scheduleSetting.setCreateTime(new Date());
        scheduleSetting.setUpdateTime(new Date());

        // 查询修改前任务
        ScheduleSetting oldJobInfo = scheduleSettingService.getById(scheduleSetting.getId());
        if (null == oldJobInfo) {
            return false;
        }
        // 修改任务
        boolean update = scheduleSettingService.updateById(scheduleSetting);
        if (!update) {
            return false;
        }
        // 修改成功,则先删除任务器中的任务,并重新添加
        SchedulingRunnable task1 = new SchedulingRunnable(oldJobInfo.getBeanName(), oldJobInfo.getMethodName(), oldJobInfo.getMethodParams());
        cronTaskRegistrar.removeCronTask(task1);
        // 如果修改后的任务状态是1就加入任务器
        if (scheduleSetting.getJobStatus().equals(1)) {
            SchedulingRunnable task = new SchedulingRunnable(scheduleSetting.getBeanName(), scheduleSetting.getMethodName(), scheduleSetting.getMethodParams());
            cronTaskRegistrar.addCronTask(task, scheduleSetting.getCronExpression());
        }
        return true;
    }

    @Override
    public boolean deleteJob(Integer id) {

        ScheduleSetting oldJobInfo = scheduleSettingService.getById(id);
        if (null == oldJobInfo) {
            return false;
        }
        // 删除
        boolean del = scheduleSettingService.removeById(id);
        if (!del){
            return false;
        }
        // 删除成功时要清除定时任务器中的对应任务
        SchedulingRunnable task = new SchedulingRunnable(oldJobInfo.getBeanName(), oldJobInfo.getMethodName(), oldJobInfo.getMethodParams());
        cronTaskRegistrar.removeCronTask(task);
        return true;
    }

    @Override
    public boolean pauseJob(Integer id) {
        return changeJobStatus(id,0);
    }

    @Override
    public boolean resumeJob(Integer id) {
        return changeJobStatus(id,1);
    }

    private boolean changeJobStatus(Integer id,Integer jobStatus) {
        // 修改任务状态
        ScheduleSetting scheduleSetting = new ScheduleSetting();
        scheduleSetting.setJobStatus(jobStatus);
        scheduleSetting.setId(id);

        boolean updateJobFlag = scheduleSettingService.updateById(scheduleSetting);
        if (!updateJobFlag) {
            return false;
        }
        // 查询修改后的任务信息
        ScheduleSetting existedSysJob = scheduleSettingService.getById(id);
        // 如果状态是1则添加任务
        if (existedSysJob.getJobStatus().equals(1)) {
            SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
            cronTaskRegistrar.addCronTask(task, existedSysJob.getCronExpression());
        } else {
            // 否则清除任务
            SchedulingRunnable task = new SchedulingRunnable(existedSysJob.getBeanName(), existedSysJob.getMethodName(), existedSysJob.getMethodParams());
            cronTaskRegistrar.removeCronTask(task);
        }
        return true;
    }
}

Controller 控制器配置

@RestController
@RequestMapping("/job")
public class JobController {
    @Resource
    private JobService jobService;


    @RequestMapping("/findAllRunJob")
    public List<ScheduleSetting> findAllRunJob()  {
        try {
            return jobService.findAllRunJob();
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * 创建定时任务
     *
     * @param scheduleSetting
     * @return
     */
    @PostMapping("create")
    public String create(@RequestBody ScheduleSetting scheduleSetting) {
        return jobService.createJob(scheduleSetting) ? "创建成功":"创建失败";
    }

    /**
     * 修改定时任务
     *
     * @param scheduleSetting
     * @return
     */
    @PostMapping("update")
    public String update(@RequestBody ScheduleSetting scheduleSetting) {
        return jobService.updateJob(scheduleSetting) ? "更新成功":"更新失败";
    }

    /**
     * 删除任务
     *
     * @param id 任务id
     * @return
     */
    @PostMapping("delete/{jobId}")
    public String del(@PathVariable("jobId") Integer id) {
        return jobService.deleteJob(id) ? "删除成功":"删除失败";
    }

    /**
     * 暂停任务
     *
     * @param id 任务id
     * @return
     */
    @PostMapping("pause/{jobId}")
    public String pause(@PathVariable("jobId") Integer id) {
        return jobService.pauseJob(id) ? "暂停成功":"暂停失败";
    }

    /**
     * 重新开始任务
     *
     * @param id 任务id
     * @return
     */
    @PostMapping("resume/{jobId}")
    public String resume(@PathVariable("jobId") Integer id) {
        return jobService.resumeJob(id) ? "重新开始任务成功":"重新开始任务失败";
    }
}

执行验证前调整

SQL 手动插入一条任务,验证 服务启动时任务启动

-- 插入一条无参的任务
INSERT INTO `schedule_setting`(`id`, `bean_name`, `method_name`, `method_params`, `cron_expression`, `remark`,
                               `job_status`, `create_time`, `update_time`)
                               VALUES (1, 'myTask1', 'execute', NULL, '1/5 * * * * ?', '无参', 1,
                                       '2023-01-05 17:12:35', '2023-01-05 17:12:38');

对任务调整

  1. 去掉日志打印
  2. 均执行有参的方法

在这里插入图片描述

执行验证

服务启动验证

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23qTwhvW-1672918382976)(images/image-20230105192213779.png)]

服务启动时, 会从数据库中读取任务进行执行。

查询所有的任务 findAllRunJob

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Dnqb8Xc-1672918382976)(images/image-20230105192510114.png)]

添加任务 create

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z0A87SPj-1672918382976)(images/image-20230105192619988.png)]

任务创建成功,但是没有启动呢。 id的编号是2

启动任务 resume

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhx5EtIp-1672918382977)(images/image-20230105192719243.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oyl25XSb-1672918382977)(images/image-20230105192746163.png)]

查看运行中的任务列表,发现是有2条的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7xHr9CJG-1672918382977)(images/image-20230105192816960.png)]

暂停任务 pause

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljZOXtTO-1672918382978)(images/image-20230105192848745.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s0L1g5gE-1672918382978)(images/image-20230105192906700.png)]

更新任务 update

修改参数 和 cron 表达式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5yfbqeV-1672918382978)(images/image-20230105192959999.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nXvXThRi-1672918382979)(images/image-20230105193035778.png)]

更新任务时, id 不会发生改变。

删除任务 delete

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uqcmposo-1672918382979)(images/image-20230105193119257.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzVitoGV-1672918382979)(images/image-20230105193140194.png)]

数据库里面也只有 myTask1 的任务

自定义动态任务是成功的。



本章节的代码放置在 github 上:


https://github.com/yuejianli/springboot/tree/develop/SpringBoot_SelfJob


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯前端二面高频手写面试题总结

实现LRU淘汰算法 LRU 缓存算法是一个非常经典的算法&#xff0c;在很多面试中经常问道&#xff0c;不仅仅包括前端面试 LRU 英文全称是 Least Recently Used&#xff0c;英译过来就是” 最近最少使用 “的意思。LRU 是一种常用的页面置换算法&#xff0c;选择最近最久未使用的…

降本提效 | AIRIOT设备运维管理解决方案

传统运维多是使用在本地化系统&#xff0c;以人工运维和独立系统执行运维工作&#xff0c;重点关注的是设施运行&#xff0c;存在以下几个问题&#xff1a; 1、信息孤岛&#xff1a;本地化系统的接口不同&#xff0c;功能单一独立&#xff0c;各个系统之间的数据无法对接、交互…

了解枚举。

在数学和计算机科学理论中&#xff0c;一个集的枚举是列出某些有穷序列集的所有成员的程序&#xff0c;或者是一种特定类型对象的计数。这两种类型经常&#xff08;但不总是&#xff09;重叠。 [1] 是一个被命名的整型常数的集合&#xff0c;枚举在日常生活中很常见&#xff0…

xxx.OpenResty+Lua后续补充

OpenRestyLua后续补充-请求参数处理看上图&#xff0c;鼠标右键-在新标签中打开图片食用 这是对xxx.nginx转发OpenResty(nginx升级版)_web服务器lua_tgbyhn31的博客-CSDN博客 的一个补充&#xff0c;用于nginx处理请求参数。 附代码&#xff1a; nginx 配置 #user nobody; w…

centos7 安装docker和docker-compose

本人使用的是 阿里云的centos7 的 镜像 安装在虚拟机里面的linux系统 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 如果这条命令没用 在国内很慢 换个地址用下面的试试 curl -sSL https://get.daocloud.io/docker | sh 安装成功 设置开机启动doc…

让你轻松掌握电商设计的在线工具,无门槛

零门槛不用经过工具认识&#xff0c;跟着教程就能上手的电商主图设计平台&#xff0c;让无基础又急需要设计电商主图的你轻松设计商品主图&#xff0c;下面跟着小编的教程一起学习如何使用乔拓云&#xff0c;在线设计电商主图&#xff01;按照步骤就能搞定&#xff01;第一步&a…

适配器Adapter

1.意图&#xff1a;将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 2.结构 类适配器结构图 对象适配器结构图 类适配器使用多重继承对一个接口与另一个接口进行匹配。对象适配器依赖于对象组合。 Targ…

职场一些办公技能和技巧总结

办公软件Word、Excel、PPT职场一些办公技能和技巧总结一、Word&#xff08;含 WPS word&#xff09;1、输入带小方框的对勾 / 叉号法1法2&#xff08;搜狗输入法&#xff09;备注&#xff1a;Word、Excel、PPT 职场一些办公技能和技巧总结一、Word&#xff08;含 WPS word&…

MySQL调优-深入理解MySQL事务隔离级别与锁机制

目录 MySQL调优-深入理解MySQL事务隔离级别与锁机制 概述 事务及其ACID属性 (1) 原子性(Atomicity) (2)一致性(Consistent) (3) 隔离性(Isolation) (4) 持久性(Durable) 原子性和一致性有何区别&#xff1f; 并发事务处理带来的问题 更新丢失(Lost Update)或脏写 脏读&…

Mysql 使用存储过程合并多个表数据

Mysql 使用存储过程合并多个表数据 drop procedure if exists mergeTable; CREATE PROCEDURE mergeTable() BEGIN#定义变量declare temp_table_name varchar(20);declare total int default 0;declare done int default false;#游标数据来源 查询出你想要合并的表名称declar…

分布式锁实现

分布式锁实现一 为什么要使用分布式锁二 分布式锁应该具备哪些条件三 分布式锁的三种实现方式四 基于数据库的实现方式五 基于Redis的实现方式一 为什么要使用分布式锁 我们在开发应用的时候&#xff0c;如果需要对某一个共享变量进行多线程同步访问的时候&#xff0c;可以使用…

HCIE-Security:顺利通过,备考心得

备考半年多&#xff0c;终于通过华为HCIE安全&#xff0c;今天把心得贴出来&#xff0c;供大家参考。 我是4月1日开始在机构开始学习安全IE的&#xff0c;报名之后从IA开始学习&#xff0c;学习期间也算勤勤恳恳&#xff0c;每次上课都进行预习和复习&#xff0c;形成自己的笔记…

论文投稿指南——中文核心期刊推荐(大气科学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

2023-1-5 javaScript

JavaScript基础 javaScript 概念 概念&#xff1a;一门客户端脚本语言 脚本语言&#xff1a;不需要编译&#xff0c;直接就可以被浏览器解析执行了 功能&#xff1a;可以增强用户和heml页面交互的过程可以控制html元素&#xff0c;让页面有一些动态的效果&#xff0c;增强用…

[AHK]腾讯实时股票数据接口

腾讯财经接口获取最新行情以五粮液为例&#xff0c;要获取最新行情&#xff0c;访问数据接口&#xff1a;qt.gtimg.cn/qsz000858返回数据&#xff1a;v_sz000858"51~五 粮 液~000858~27.78~27.60~27.70~417909~190109~227800~27.78~492~27.77~332~27.76~202~27.75~334~27.…

[ERROR] Malformed \uxxxx encoding.报错解决

今天用idea运行完项目。想直接打包的时候&#xff0c;结果打包失败&#xff0c;一直报错 [ERROR] Malformed \uxxxx encoding. 网上查了之后&#xff0c;一直说是&#xff0c;有路径在使用斜杠的时候&#xff0c;使用错误。将"\“换成”/“就好了&#xff0c;但是我配置文…

pb将字符串中的中文和英文(含符号)拆分

//用于将字符串中的中文和英文(含符号)拆分 //uf_split_str_enorcn(as_inputstr) //as_inputstr:导入字符串 long i, li_len, li_lenA as_return_cn = as_return_en = if as_inputstr > then li_len = len(as_inputstr) //带中文长度 li_lenA = lenA…

ICMP隧道-调研笔记

ICMP隧道通信原理与通信特征 https://baijiahao.baidu.com/s?id1652047934643855432&wfrspider&forpc 1.一个正常的 ping每秒最多只会发送两个数据包&#xff0c;而使用ICMP隧道的浏览器在同一时间会产生大量ICMP 数据包 2.ICMP隧道数据包中DATA 往往大于64 比特 3.正…

TC275-11CCU6_PWM_Generation

基础知识 CCU6&#xff0c;Capture/Compare Unit 6捕获/比较单元&#xff0c;是一个专门用于电机控制而设计的16位捕获和比较单元。 CCU6包含多个定时器&#xff0c;将它们的计数值和参考值进行比较&#xff0c;来生成PWM信号。 定时器12&#xff08;T12&#xff09;配有三个…