1. 分布式任務(wù)調(diào)度有那么難嗎?來(lái),10分鐘帶你實(shí)戰(zhàn)

        共 14408字,需瀏覽 29分鐘

         ·

        2021-09-17 21:23

        一、概述

        1.1、什么是任務(wù)調(diào)度

        我們可以思考一下下面業(yè)務(wù)場(chǎng)景的解決方案:

        • 某電商平臺(tái)需要每天上午10點(diǎn),下午3點(diǎn),晚上8點(diǎn)發(fā)放一批優(yōu)惠券

        • 某銀行系統(tǒng)需要在信用卡到期還款日的前三天進(jìn)行短信提醒

        • 某財(cái)務(wù)系統(tǒng)需要在每天凌晨0:10分結(jié)算前一天的財(cái)務(wù)數(shù)據(jù),統(tǒng)計(jì)匯總

        以上場(chǎng)景就是任務(wù)調(diào)度所需要解決的問(wèn)題,任務(wù)調(diào)度是為了自動(dòng)完成特定任務(wù),在約定的特定時(shí)刻去執(zhí)行任務(wù)的過(guò)程。

        在Spring中也提供了定時(shí)任務(wù)注解@Scheduled。我們只需要在業(yè)務(wù)中貼上注解然后在啟動(dòng)類上貼上@EnableScheduling注解即可完成任務(wù)調(diào)度功能。

        @Scheduled(cron = "0/20 * * * * ? ") // 每隔20秒執(zhí)行一次
        public void doWork(){
        //doSomething
        }
        復(fù)制代碼

        1.2、分布式調(diào)度出現(xiàn)

        感覺(jué)Spring給我們提供的這個(gè)注解可以完成任務(wù)調(diào)度的功能,好像已經(jīng)完美解決問(wèn)題了,為什么還需要分布式呢?主要的原因有以下幾點(diǎn):

        1. 機(jī)處理極限:原本1分鐘內(nèi)需要處理1萬(wàn)個(gè)訂單,但是現(xiàn)在需要1分鐘內(nèi)處理10萬(wàn)個(gè)訂單;原來(lái)一個(gè)統(tǒng)計(jì)需要1小時(shí),現(xiàn)在業(yè)務(wù)方需要10分鐘就統(tǒng)計(jì)出來(lái)。你也許會(huì)說(shuō),你也可以多線程、單機(jī)多進(jìn)程處理。的確,多線程并行處理可以提高單位時(shí)間的處理效率,但是單機(jī)能力畢竟有限(主要是CPU、內(nèi)存和磁盤(pán)),始終會(huì)有單機(jī)處理不過(guò)來(lái)的情況。

        2. 高可用:?jiǎn)螜C(jī)版的定式任務(wù)調(diào)度只能在一臺(tái)機(jī)器上運(yùn)行,如果程序或者系統(tǒng)出現(xiàn)異常就會(huì)導(dǎo)致功能不可用。雖然可以在單機(jī)程序?qū)崿F(xiàn)的足夠穩(wěn)定,但始終有機(jī)會(huì)遇到非程序引起的故障,而這個(gè)對(duì)于一個(gè)系統(tǒng)的核心功能來(lái)說(shuō)是不可接受的。

        3. 防止重復(fù)執(zhí)行: 在單機(jī)模式下,定時(shí)任務(wù)是沒(méi)什么問(wèn)題的。但當(dāng)我們部署了多臺(tái)服務(wù),同時(shí)又每臺(tái)服務(wù)又有定時(shí)任務(wù)時(shí),若不進(jìn)行合理的控制在同一時(shí)間,只有一個(gè)定時(shí)任務(wù)啟動(dòng)執(zhí)行,這時(shí),定時(shí)執(zhí)行的結(jié)果就可能存在混亂和錯(cuò)誤了。

        1.3、Elastic-Job

        Elastic-Job是一個(gè)分布式調(diào)度的解決方案,由當(dāng)當(dāng)網(wǎng)開(kāi)源,它由兩個(gè)相互獨(dú)立的子項(xiàng)目Elastic-job-Lite和Elastic-Job-Cloud組成,使用Elastic-Job可以快速實(shí)現(xiàn)分布式任務(wù)調(diào)度。Elastic-Job的github地址。他的功能主要是:

        • 分布式調(diào)度協(xié)調(diào)

          在分布式環(huán)境中,任務(wù)能夠按照指定的調(diào)度策略執(zhí)行,并且能夠避免同一任務(wù)多實(shí)例重復(fù)執(zhí)行。

        • 豐富的調(diào)度策略:

          基于成熟的定時(shí)任務(wù)作業(yè)框架Quartz cron表達(dá)式執(zhí)行定時(shí)任務(wù)。

        • 彈性拓容縮容

          當(dāng)集群中增加一個(gè)實(shí)例,它應(yīng)當(dāng)能夠被選舉被執(zhí)行任務(wù);當(dāng)集群減少一個(gè)實(shí)例時(shí),他所執(zhí)行的任務(wù)能被轉(zhuǎn)移到別的示例中執(zhí)行。

        • 失效轉(zhuǎn)移

          某示例在任務(wù)執(zhí)行失敗后,會(huì)被轉(zhuǎn)移到其他實(shí)例執(zhí)行。

        • 錯(cuò)過(guò)執(zhí)行任務(wù)重觸發(fā)

          若因某種原因?qū)е伦鳂I(yè)錯(cuò)過(guò)執(zhí)行,自動(dòng)記錄錯(cuò)誤執(zhí)行的作業(yè),并在下次次作業(yè)完成后自動(dòng)觸發(fā)。

        • 支持并行調(diào)度

          支持任務(wù)分片,任務(wù)分片是指將一個(gè)任務(wù)分成多個(gè)小任務(wù)在多個(gè)實(shí)例同時(shí)執(zhí)行。

        • 作業(yè)分片一致性

          當(dāng)任務(wù)被分片后,保證同一分片在分布式環(huán)境中僅一個(gè)執(zhí)行實(shí)例。

        • 支持作業(yè)生命周期操作

          可以動(dòng)態(tài)對(duì)任務(wù)進(jìn)行開(kāi)啟及停止操作。

        • 豐富的作業(yè)類型

          支持Simple、DataFlow、Script三種作業(yè)類型

        1.4、啟動(dòng)zookeeper

        1. 解壓包

        2. 到conf目錄中把oo_sample.cfg 拷貝一份 , 修改名字為zoo.cfg。

        3. 到bin目錄中啟動(dòng)startup.cmd文件(用1命令行啟動(dòng))。

        1.4、啟動(dòng)zookeeper圖形化界面

        1. 解壓。

        2. 到1build目錄中,找到j(luò)ar包。

        3. 使用命令:java -jar jar包的名字

        二、Elastic-Job快速入門(mén)

        Elastic-Job的1環(huán)境要求:

        • JDK 要求1.7以上保本

        • Maven 要求3.0.4及以上版本

        • Zookeeper 要求采取3.4.6以上版本

        2.1、環(huán)境搭建

        安裝運(yùn)行zookeeper

        創(chuàng)建一個(gè)maven項(xiàng)目并導(dǎo)入依賴

        <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>elastic-job-lite-core</artifactId>
        <version>2.1.5</version>
        </dependency>
        復(fù)制代碼

        寫(xiě)任務(wù)類

        public class XiaoLinJob implements SimpleJob {

        // 寫(xiě)任務(wù)類
        @Override
        public void execute(ShardingContext shardingContext) {
        System.out.println("定時(shí)任務(wù)開(kāi)始");
        }
        }
        復(fù)制代碼

        編寫(xiě)配置類

        public class JobDemo {

        public static void main(String[] args) {
        new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();
        }
        private static CoordinatorRegistryCenter createRegistryCenter() {
        //配置zk地址,調(diào)度任務(wù)的組名
        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("127.0.0.1:2181", "elastic-job-demo");
        zookeeperConfiguration.setSessionTimeoutMilliseconds(1000);
        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
        regCenter.init();
        return regCenter;
        }

        private static LiteJobConfiguration createJobConfiguration() {
        // 定義作業(yè)核心配置
        JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("demoSimpleJob","0/1 * * * * ?",1).build();
        // 定義SIMPLE類型配置
        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, XiaoLinJob.class.getCanonicalName());
        // 定義Lite作業(yè)根配置
        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
        return simpleJobRootConfig;
        }
        }
        復(fù)制代碼

        2.2、測(cè)試

        1. 當(dāng)只有一臺(tái)啟動(dòng)的時(shí)候,按照corn表達(dá)式進(jìn)行任務(wù)調(diào)度。

        2. 開(kāi)啟兩臺(tái)機(jī)器的1時(shí)候,新開(kāi)的一臺(tái)會(huì)繼續(xù)執(zhí)行定時(shí)任務(wù),舊的1那一臺(tái)會(huì)停止。

        三、SpringBoot集成Elastic-Job

        3.1、引入依賴

         <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        </parent>

        <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
        <groupId>com.dangdang</groupId>
        <artifactId>elastic-job-lite-spring</artifactId>
        <version>2.1.5</version>
        </dependency>
        <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        </dependency>
        </dependencies>
        復(fù)制代碼

        3.2、編寫(xiě)配置文件

        application.yaml

        因?yàn)榕渲弥行牡牡刂凡皇枪潭ǖ模晕覀儾荒軐?xiě)死在代碼中,需要把他寫(xiě)在配置文件中。新建一個(gè)配置文件:

        elasticjob:
        zookeeper-url: localhost:2181
        group-name: elastic-job-group
        復(fù)制代碼

        zookeeper注冊(cè)中心配置類

        // 注冊(cè)中心的配置類
        @Configuration
        public class RegistryCenterConfig {

        @Bean(initMethod = "init")
        // 從配置文件中獲取注冊(cè)中心的的url和命名空間
        public CoordinatorRegistryCenter coordinatorRegistryCenter(
        @Value("${elasticjob.zookeeper-url}") String zookeeperUrl,
        @Value("${elasticjob.group-name}") String namespace)
        {
        // zk的配置
        ZookeeperConfiguration zookeeperConfiguration =
        new ZookeeperConfiguration(zookeeperUrl,namespace);
        // 設(shè)置超時(shí)時(shí)間
        zookeeperConfiguration.setMaxSleepTimeMilliseconds(10000000);
        // 創(chuàng)建注冊(cè)中心
        ZookeeperRegistryCenter zookeeperRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
        return zookeeperRegistryCenter;
        }
        }
        復(fù)制代碼

        任務(wù)調(diào)度的配置類

        @Configuration
        public class JobConfig {

        @Autowired
        XiaoLinJob xiaoLinJob;

        @Autowired
        private CoordinatorRegistryCenter registryCenter;
        private static LiteJobConfiguration createJobConfiguration(
        final Class<? extends SimpleJob> jobClass, // 任務(wù)的名字
        final String cron, // cron表達(dá)式
        final int shardingTotalCount, // 分片的數(shù)量
        final String shardingItemParameters // 分片類信奉的參數(shù)
        )
        {
        JobCoreConfiguration.Builder jobCoreConfigurationBuilder = JobCoreConfiguration.newBuilder(jobClass.getSimpleName(),cron,shardingTotalCount);
        if(!StringUtils.isEmpty(shardingItemParameters)){
        jobCoreConfigurationBuilder.shardingItemParameters(shardingItemParameters);
        }
        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(jobCoreConfigurationBuilder.build(), XiaoLinJob.class.getCanonicalName());
        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).overwrite(true).build();
        return simpleJobRootConfig;

        }
        @Bean(initMethod = "init")
        public SpringJobScheduler initSimpleElasticJob(){
        SpringJobScheduler springJobScheduler = new SpringJobScheduler(xiaoLinJob,registryCenter,createJobConfiguration(XiaoLinJob.class,"0/3 * * * * ?",1,null));
        return springJobScheduler;
        }

        }
        復(fù)制代碼

        自定義任務(wù)類

        @Component
        public class XiaoLinJob implements SimpleJob {

        @Override
        public void execute(ShardingContext shardingContext) {
        System.out.println("============");
        }
        }
        復(fù)制代碼

        3.3、測(cè)試

        四、小案例

        4.1、單機(jī)版本

        4.1.1、需求描述

        數(shù)據(jù)庫(kù)中有一些列的數(shù)據(jù),需要對(duì)這些數(shù)據(jù)進(jìn)行備份操作,備份完之后,修改數(shù)據(jù)的狀態(tài),標(biāo)記已經(jīng)備份了。

        4.1.2、創(chuàng)建數(shù)據(jù)庫(kù)

        SET FOREIGN_KEY_CHECKS=0;

        -- ----------------------------
        -- Table structure for t_file_custom
        -- ----------------------------
        DROP TABLE IF EXISTS `t_file_custom`;
        CREATE TABLE `t_file_custom` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT,
        `name` varchar(255) DEFAULT NULL,
        `content` varchar(255) DEFAULT NULL,
        `type` varchar(255) DEFAULT NULL,
        `backedUp` tinyint(4) DEFAULT NULL,
        PRIMARY KEY (`id`)
        ) ENGINE
        =InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

        -- ----------------------------
        -- Records of t_file_custom
        -- ----------------------------
        INSERT INTO `t_file_custom` VALUES ('1', '文件1', '內(nèi)容1', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('2', '文件2', '內(nèi)容2', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('3', '文件3', '內(nèi)容3', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('4', '文件4', '內(nèi)容4', 'image', '1');
        INSERT INTO `t_file_custom` VALUES ('5', '文件5', '內(nèi)容5', 'image', '1');
        INSERT INTO `t_file_custom` VALUES ('6', '文件6', '內(nèi)容6', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('7', '文件6', '內(nèi)容7', 'radio', '1');
        INSERT INTO `t_file_custom` VALUES ('8', '文件8', '內(nèi)容8', 'radio', '1');
        INSERT INTO `t_file_custom` VALUES ('9', '文件9', '內(nèi)容9', 'vedio', '1');
        INSERT INTO `t_file_custom` VALUES ('10', '文件10', '內(nèi)容10', 'vedio', '1');
        INSERT INTO `t_file_custom` VALUES ('11', '文件11', '內(nèi)容11', 'vedio', '1');
        INSERT INTO `t_file_custom` VALUES ('12', '文件12', '內(nèi)容12', 'vedio', '1');
        INSERT INTO `t_file_custom` VALUES ('13', '文件13', '內(nèi)容13', 'image', '1');
        INSERT INTO `t_file_custom` VALUES ('14', '文件14', '內(nèi)容14', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('15', '文件15', '內(nèi)容15', 'image', '1');
        INSERT INTO `t_file_custom` VALUES ('16', '文件16', '內(nèi)容16', 'text', '1');
        INSERT INTO `t_file_custom` VALUES ('17', '文件17', '內(nèi)容17', 'radio', '1');
        INSERT INTO `t_file_custom` VALUES ('18', '文件18', '內(nèi)容18', 'image', '1');
        INSERT INTO `t_file_custom` VALUES ('19', '文件19', '內(nèi)容19', 'radio', '1');
        INSERT INTO `t_file_custom` VALUES ('20', '文件20', '內(nèi)容20', 'vedio', '1');

        復(fù)制代碼

        4.1.3、Druid&MyBatis

        4.1.3.1、添加依賴

                <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
        </dependency>
        <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.2.0</version>
        </dependency>
        <!--mysql驅(qū)動(dòng)-->
        <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        </dependency>
        復(fù)制代碼

        4.1.3.2、集成數(shù)據(jù)庫(kù)

        spring:
        datasource:
        url: jdbc:mysql://localhost:3306/elastic-job-demo?serverTimezone=GMT%2B8
        driverClassName: com.mysql.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
        password: admin
        復(fù)制代碼

        4.1.4、添加實(shí)體類

        @Data
        public class FileCustom {
        //唯一標(biāo)識(shí)
        private Long id;
        //文件名
        private String name;
        //文件類型
        private String type;
        //文件內(nèi)容
        private String content;
        //是否已備份
        private Boolean backedUp = false;
        public FileCustom(){}
        public FileCustom(Long id, String name, String type, String content){
        this.id = id;
        this.name = name;
        this.type = type;
        this.content = content;
        }
        }
        復(fù)制代碼

        4.1.5、添加任務(wù)類

        @Slf4j
        @Component
        public class FileCustomElasticJob implements SimpleJob {

        @Autowired
        FileCopyMapper fileCopyMapper;

        @Override
        public void execute(ShardingContext shardingContext) {
        doWork();
        }

        private void doWork() {
        List<FileCustom> fileCustoms = fileCopyMapper.selectAll();
        if (fileCustoms.size() == 0){
        log.info("備份完成");
        return;
        }
        log.info("需要備份的文件個(gè)數(shù)為:"+fileCustoms.size());
        for (FileCustom fileCustom : fileCustoms) {
        backUpFile(fileCustom);
        }
        }

        private void backUpFile(FileCustom fileCustom) {
        try {
        Thread.sleep(1000);
        log.info("執(zhí)行備份文件:"+fileCustom);
        fileCopyMapper.backUpFile(fileCustom.getId());

        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        }
        復(fù)制代碼

        4.1.6、添加Mapper

        @Mapper
        public interface FileCopyMapper {

        @Select("select * from t_file_custom where backedUp = 0")
        List<FileCustom> selectAll();

        @Update("update t_file_custom set backedUp = 1 where id = #{id}")
        void backUpFile(Long id);
        }
        復(fù)制代碼

        4.1.7、添加任務(wù)調(diào)度配置

          @Bean(initMethod = "init")
        public SpringJobScheduler initFileCustomElasticJob(FileCustomElasticJob fileCustomElasticJob){
        SpringJobScheduler springJobScheduler = new SpringJobScheduler(fileCustomElasticJob,registryCenter,createJobConfiguration(XiaoLinJob.class,"0/3 * * * * ?",1,null));
        return springJobScheduler;
        }
        復(fù)制代碼

        4.1.8、存在的問(wèn)題

        為了高可用,我們會(huì)對(duì)這個(gè)項(xiàng)目做集群的操作,可以保證其中一臺(tái)掛了,另外一臺(tái)可以繼續(xù)工作.但是在集群的情況下,調(diào)度任務(wù)只在一臺(tái)機(jī)器上運(yùn)行,如果單個(gè)任務(wù)調(diào)度比較耗時(shí),耗資源的情況下,對(duì)這臺(tái)機(jī)器的消耗還是比較大的。

        但是這個(gè)時(shí)候,其他機(jī)器卻是空閑著的,如何合理的利用集群的其他機(jī)器且如何讓任務(wù)執(zhí)行得更快些呢?這時(shí)候Elastic-Job提供了任務(wù)調(diào)度分片的功能。

        4.2、集群版本

        4.2.1、分片概念

        作業(yè)分片是指任務(wù)的分布式執(zhí)行,需要將一個(gè)任務(wù)拆分為多個(gè)獨(dú)立的任務(wù)項(xiàng),然后由分布式的應(yīng)用實(shí)例分別執(zhí)行某一個(gè)或者幾個(gè)分布項(xiàng)。

        例如在單機(jī)版本的備份數(shù)據(jù)的案例,如果有兩臺(tái)服務(wù)器,每臺(tái)服務(wù)器分別跑一個(gè)應(yīng)用實(shí)例。為了快速執(zhí)行作業(yè),那么可以講任務(wù)分成4片,每個(gè)應(yīng)用實(shí)例都執(zhí)行兩片。作業(yè)遍歷數(shù)據(jù)邏輯應(yīng)為:實(shí)例1查找text和image類型文件執(zhí)行備份,實(shí)例2查找radio和vedio類型文件執(zhí)行備份。

        如果由于服務(wù)器拓容應(yīng)用實(shí)例數(shù)量增加為4,則作業(yè)遍歷數(shù)據(jù)的邏輯應(yīng)為: 4個(gè)實(shí)例分別處理text、image、radio、video類型的文件。

        通過(guò)對(duì)任務(wù)的合理分片化,從而達(dá)到任務(wù)并行處理的效果,他的好處是:

        1. 分片項(xiàng)與業(yè)務(wù)處理解耦:Elastic-Job并不直接提供數(shù)據(jù)處理的功能,框架只會(huì)將分片項(xiàng)分配至各個(gè)運(yùn)行中的作業(yè)服務(wù)器,開(kāi)發(fā)者需要自行處理分片項(xiàng)與真實(shí)數(shù)據(jù)的對(duì)應(yīng)關(guān)系。

        2. 最大限度利用資源:將分片項(xiàng)設(shè)置大于服務(wù)器的數(shù)據(jù),最好是大于服務(wù)器倍數(shù)的數(shù)量,作業(yè)將會(huì)合理利用分布式資源,動(dòng)態(tài)的分配分片項(xiàng)。例如:3臺(tái)服務(wù)器,分成10片,則分片項(xiàng)結(jié)果為服務(wù)器A=0、1、2。服務(wù)器B=3、4、5。服務(wù)器C=6、7、8、9。如果   服務(wù)器C奔潰,則分片項(xiàng)分配結(jié)果為服務(wù)器A=0、1、2、3、4。服務(wù)器B=5、6、7、8、9。在不丟失分片項(xiàng)的情況下,最大限度利用現(xiàn)有的資源提高吞吐量。

        4.2.2、配置類修改

        如果想將單機(jī)版本改為集群版本,我們首先需要在任務(wù)配置類中增加分片個(gè)數(shù)以及分片參數(shù)。

        @Bean(initMethod = "init")
        public SpringJobScheduler initFileCustomElasticJob(FileCustomElasticJob fileCustomElasticJob){
        SpringJobScheduler springJobScheduler = new
        //第一個(gè)參數(shù)表示自定義任務(wù)類,第二個(gè)參數(shù)是corn表達(dá)式,第三個(gè)參數(shù)是分片個(gè)數(shù),第四個(gè)參數(shù)是分片的名稱,第一個(gè)分片作用是查詢類型為test的,以此類推
        SpringJobScheduler(fileCustomElasticJob,registryCenter,createJobConfiguration(XiaoLinJob.class,"0/3 * * * * ?",4,"0=text,1=image,2=radio,3=vedio"));
        return springJobScheduler;
        }
        復(fù)制代碼

        4.2.3、 新增作業(yè)分片邏輯

        @Slf4j
        @Component
        public class FileCustomElasticJob implements SimpleJob {

        @Autowired
        FileCopyMapper fileCopyMapper;

        @Override
        public void execute(ShardingContext shardingContext) {
        // 獲取到指定分片的類型
        doWork(shardingContext.getShardingParameter());
        }

        private void doWork(String fileType) {
        List<FileCustom> fileCustoms = fileCopyMapper.selectByType(fileType);
        if (fileCustoms.size() == 0){
        log.info("備份完成");
        return;
        }
        log.info("需要備份的文件類型是:"+fileType+"文件個(gè)數(shù)為:"+fileCustoms.size());
        for (FileCustom fileCustom : fileCustoms) {
        backUpFile(fileCustom);
        }
        }

        private void backUpFile(FileCustom fileCustom) {
        try {
        Thread.sleep(2000);
        log.info("執(zhí)行備份文件:"+fileCustom);
        fileCopyMapper.backUpFile(fileCustom.getId());

        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        }
        }
        復(fù)制代碼

        4.2.4、Mapper類修改

        @Mapper
        public interface FileCopyMapper {

        @Select("select * from t_file_custom where backedUp = 0")
        List<FileCustom> selectAll();

        @Update("update t_file_custom set backedUp = 1 where id = #{id}")
        void backUpFile(Long id);

        @Select("select * from t_file_custom where backedUp = 0 and type = #{fileType}")
        List<FileCustom> selectByType(String fileType);
        }
        復(fù)制代碼

        4.2.5、測(cè)試

        4.2.5.1、一臺(tái)機(jī)器

        一臺(tái)機(jī)器啟動(dòng)四個(gè)線程直接跑完。

        4.2.5.2、四臺(tái)機(jī)器

        當(dāng)四臺(tái)機(jī)器啟動(dòng)的時(shí)候,每臺(tái)機(jī)器分得一個(gè)線程,查詢并備份一種類型的數(shù)據(jù)。

        ----------------------------------------------------------我是分割線----------------------------------------------------------

        ----------------------------------------------------------我是分割線----------------------------------------------------------

        ----------------------------------------------------------我是分割線----------------------------------------------------------


        作者:XiaoLin_Java
        鏈接:https://juejin.cn/post/7007058861379190821
        來(lái)源:掘金
        著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。



        瀏覽 27
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 亚洲久久天堂 | 亚洲AV无码精品成人影院麻豆 | 国产特级全黄一级97毛片 | 扒开美女狂揉动漫原神 | 国产一级黄色电影 |