目錄
問題內容
解決方法
首頁 Java 嘗試同時啟動兩個或多個 Spring Batch 作業時,會拋出錯誤:ORA-08177: 無法序列化此事務的訪問

嘗試同時啟動兩個或多個 Spring Batch 作業時,會拋出錯誤:ORA-08177: 無法序列化此事務的訪問

Feb 09, 2024 pm 05:00 PM
lsp

php小編西瓜在使用Spring Batch時,可能會遇到一個問題:當嘗試同時啟動兩個或多個Spring Batch作業時,會拋出錯誤:ORA-08177: 無法序列化此事務的訪問。這個錯誤可能會讓人感到困惑,但實際上它是由於資料庫鎖定問題導致的。在解決這個問題之前,我們需要先了解一些關於Spring Batch和資料庫事務的背景知識。

問題內容

嘗試使用 completablefuture 並行執行兩個 spring batch 作業時遇到錯誤。錯誤訊息如下:

originalsql = insert into batch_job_instance(job_instance_id, job_name, job_key, version)
    values (?, ?, ?, ?)
, error msg = ora-08177: can't serialize access for this transaction
登入後複製

我正在使用 spring batch 5.x、spring boot 3.1.6、jdk 17

應用程式屬性

spring.batch.repository.isolationlevelforcreate=isolation_read_committed
spring.batch.isolationlevel=read_committed
spring.batch.jdbc.table-prefix=batch_
spring.batch.job.enabled=false
登入後複製

batchconfig.java

@configuration
public class batchconfig {

@bean("simpletaskexecutor")
    public taskexecutor simpletaskexecutor() {
        simpleasynctaskexecutor asynctaskexecutor = new simpleasynctaskexecutor("simpletaskexecutor");
        asynctaskexecutor.setconcurrencylimit(concurrencycount);
        return asynctaskexecutor;
    }


@bean("joblauncherasync")
    @scope("prototype")
    public joblauncher joblauncherasync(datasource datasource, jobrepository jobrepository) throws exception {

        taskexecutorjoblauncher joblauncher = new taskexecutorjoblauncher();
        joblauncher.setjobrepository(jobrepository);
        joblauncher.settaskexecutor(simpletaskexecutor());
        joblauncher.afterpropertiesset();
        return joblauncher;
    }
    
    @bean
    public jpatransactionmanager transactionmanager(entitymanagerfactory entitymanagerfactory) {
        return new jpatransactionmanager(entitymanagerfactory);
    }
    
    @bean
    public batchjobexecutionlistener batchjobexecutionlistener() {
        return new batchjobexecutionlistener();
    } 
    
    @bean
    public batchjobstepexecutionlistner batchjobstepexecutionlistner() {
        return new batchjobstepexecutionlistner();
    }
登入後複製

}

employeejobconfig.java

#
@configuration
@import(batchconfig.class)
public class employeejobconfig{
    
        
    @autowired
    employeestatuswritter employeestatuswritter;
    
    @autowired
    employeependingprocessor employeependingprocessor;
    
    
    
    @bean("employeependingreader")
    public jpapagingitemreader<employee> employeependingreader(datasource ds,entitymanagerfactory entitymanagerfactory) {
        
        jpapagingitemreader<employee> jpareader = new jpapagingitemreader<>();
        jpareader.setentitymanagerfactory(entitymanagerfactory);
        jpareader.setquerystring("select e from employee e");
        jpareader.setpagesize(5000);
        return jpareader;

    }
    
    @bean("employeespinvokestep")
    public step employeespinvokestep(@qualifier("employeependingreader") itemreader<employee> reader,
            @qualifier("employeestatuswritter") itemwriter<employee> writer,
            @qualifier("employeependingprocessor") itemprocessor<employee, employee> processor,jobrepository jobrepository,
            platformtransactionmanager transactionmanager,batchjobstepexecutionlistner batchjobstepexecutionlistner,taskexecutor simpletaskexecutor) {

        return new stepbuilder("employeespinvokestep",jobrepository)
                .<employee, employee>chunk(50,transactionmanager).reader(reader)
                .processor(processor).writer(writer)
                .listener(batchjobstepexecutionlistner)
                .taskexecutor(simpletaskexecutor)
                .build();
    }
    
    @bean("employeespjob")
    public job employeespjob(@qualifier("employeespinvokestep") step employeespinvokestep,jobrepository jobrepository,batchjobexecutionlistener batchjobexecutionlistener) {
        return new jobbuilder("employeespjob",jobrepository)
                .incrementer(new runidincrementer())
                .listener(batchjobexecutionlistener)
                .start(employeespinvokestep)
                .build();
    }

}
登入後複製

managerconfig.java

@configuration
@import(batchconfig.class)
public class managerconfig {
    
        

    @autowired
    managerstatuswritter managerstatuswritter;
    
    
    @autowired
    managerpendingprocessor managerpendingprocessor;
    
    @bean("managerpendingreader")
    public jpapagingitemreader<manager> managerpendingreader(datasource ds,entitymanagerfactory entitymanagerfactory) {
        
        jpapagingitemreader<manager> jpareader = new jpapagingitemreader<>();
        jpareader.setentitymanagerfactory(entitymanagerfactory);
        jpareader.setquerystring("select m from manager m");
        jpareader.setpagesize(5000);
        return jpareader;

    }
    
    @bean("managerspinvokestep")
    public step indvinvoiceconsctlspinvokestep(@qualifier("managerpendingreader") itemreader<manager> reader,
            @qualifier("managerstatuswritter") itemwriter<manager> writer,
            @qualifier("managerpendingprocessor") itemprocessor<manager, manager> processor,jobrepository jobrepository,
            platformtransactionmanager transactionmanager,batchjobstepexecutionlistner batchjobstepexecutionlistner,taskexecutor simpletaskexecutor) {

        return new stepbuilder("managerspinvokestep",jobrepository)
                .<manager, manager>chunk(5000,transactionmanager).reader(reader)
                .processor(processor).writer(writer)
                .listener(batchjobstepexecutionlistner)
                .taskexecutor(simpletaskexecutor)
                .build();
    }
    
    @bean("managerspjob")
    public job managerspjob(@qualifier("managerspinvokestep") step indvinvoiceconsctlspinvokestep,jobrepository jobrepository,batchjobexecutionlistener batchjobexecutionlistener) {
        return new jobbuilder("managerspjob",jobrepository)
                .incrementer(new runidincrementer())
                .listener(batchjobexecutionlistener)
                .start(indvinvoiceconsctlspinvokestep)
                .build();
    }
    
}
登入後複製

batchjobmanager.java

#
@service
public class batchjobmanager {

    
    
      @autowired applicationcontext context;
     
      @autowired batchexecutorservice batchexecutorservice;
      
      @autowired
      batchjobrunner batchjobrunner;
      
       
    
    public void startjob() {
        
         try {
               system.out.println("batchjobmanager called .. "+new date());
                
               string[] invoicenames={"employeespjob","managerspjob"};
               
               list<string> invoicenameslist = arrays.aslist(invoicenames);
               launchasyn(getbatchjoblist(invoicenameslist));
                
                 
         } catch (exception e) {
             system.out.println("while loading job..");
             e.printstacktrace();
         }
        
    }
      

    public list<batchjob>  getbatchjoblist(list<string> jobnames) throws exception{
        list<batchjob> batchjoblist=new arraylist<batchjob>();
        for(string job:jobnames) {
             batchjob batchjob= batchjob.builder().jobname(invoicejob).build();
             batchjoblist.add(batchjob);
        }
        return batchjoblist;
    }
      
    
       
    public void launchasyn( list<batchjob> batchjoblist) throws exception{
         list<completablefuture<batchjob>> batchjobfuturelist = new arraylist<completablefuture<batchjob>>();
          
          for(batchjob batchjob:batchjoblist) {
          completablefuture<batchjob> jobfuture = batchexecutorservice.execute(batchjob, asynctaskexecutor);
          batchjobfuturelist.add(jobfuture);
          }
          
          completablefuture<void> jobfutureresult = completablefuture
                    .allof(batchjobfuturelist.toarray(new completablefuture[batchjobfuturelist.size()]));
          
          
          completablefuture<list<canbatchjob>> allcompletablefuture = jobfutureresult.thenapply(future -> {
                return batchjobfuturelist.stream().map(completablefuture -> completablefuture.join())
                        .collect(collectors.tolist());
            });
        
          list<batchjob> resultfuturelist=allcompletablefuture.get();
          
          for(batchjob batch:resultfuturelist) {
              system.out.println("status "+batch.getiscompleted());
          }
    }
   
    
}
登入後複製

batchexecutorservice.java

@service
public class batchexecutorservice {
    
        
    @autowired 
    batchjobrunner batchjobrunner;
        
    public completablefuture<canbatchjob> execute(canbatchjob canbatchjob,taskexecutor threadpooltaskexecutor){
        return completablefuture.supplyasync(() -> batchjobrunner.execute(canbatchjob),threadpooltaskexecutor);
    }
    
    
}
登入後複製

batchjobrunner.java

#
@service
public class batchjobrunner {

    @autowired applicationcontext context;
      
    
     @autowired 
     @qualifier("joblauncherasync")
     joblauncher joblauncherasync;
    
    
    /*
     * @autowired joblauncher joblauncherasync;
     */
    
    public batchjob execute(batchjob batchjob) {
        try {
            system.out.println(" batchjob"+batchjob.getjobname()+" called ...");
            joblauncherasync.run(getjob(batchjob.getjobname()), getjobparameters(batchjob.getjobname()));
            thread.sleep(15000);
            batchjob.setiscompleted(true);
            system.out.println(" batchjob"+batchjob.getjobname()+" completed ...");
        }
        catch(exception e) {
            system.out.println("exception "+e.getmessage());
            batchjob.seterrordesc(e.getmessage().tostring());
            e.printstacktrace();
        }
        
        return canbatchjob;
    }
    
    public job getjob(string jobname) {
        
         return  (job) context.getbean(jobname); 
    }
    
    public jobparameters getjobparameters(string jobname) {
    
    jobparameters  jobparameters = new jobparametersbuilder() .addstring("unique_id",
              uuid.randomuuid().tostring(), true) .addstring("job_name", jobname,
              true) .adddate("execution_start_date", date.from(instant.now()),
              true).tojobparameters();
    return jobparameters;
    }
    
}
登入後複製

batchjob.java

public class BatchJob {

    private String jobName;
    private Boolean isCompleted;
    private String errorDesc;
    
    
}
登入後複製

作業在逐一或依序執行時成功執行。但是,在使用 completablefuture 時,遇到了問題。同時啟動 spring 批次作業是正確的方法嗎?

解決方法

1.將下列屬性新增至application.properties

#spring.main.allow-bean-definition-overriding=true

2.更新了 joblauncher(),如下 batchconfig.java 所示

@bean("joblauncher")
    public joblauncher joblauncher(datasource datasource, jobrepository jobrepository) throws exception {
        taskexecutorjoblauncher joblauncher = new taskexecutorjoblauncher();
        joblauncher.setjobrepository(jobrepository);
        joblauncher.settaskexecutor(simpletaskexecutor());
        joblauncher.afterpropertiesset();
        return joblauncher;
    }
登入後複製
  • 刪除了 completablefuture。

  • 刪除了 batchexecutorservice.java

  • 在 batchjobmanager.java 中新增了以下方法來呼叫作業。

    public void launchSync(List<BatchJob> batchJobList) throws Exception {
             for(BatchJob batchJob:batchJobList) {
                  batchJobRunner.execute(batchJob);
                  }  
         }
    登入後複製

    以上是嘗試同時啟動兩個或多個 Spring Batch 作業時,會拋出錯誤:ORA-08177: 無法序列化此事務的訪問的詳細內容。更多資訊請關注PHP中文網其他相關文章!

  • 本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
    威爾R.E.P.O.有交叉遊戲嗎?
    1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    紅米Note13RPro怎麼隱藏相簿? 紅米Note13RPro怎麼隱藏相簿? May 01, 2024 pm 12:50 PM

    RedmiNote13RPro是一款性能配置非常不錯的全新機型,這款手機中有一個隱藏相簿的功能十分好用,它可以幫助用戶將相簿隱藏起來,讓別人無法查看你的相簿。接下來,小編就來跟大家說紅米Note13RPro怎麼隱藏相冊,幫助大家保護隱私。紅米Note13RPro怎麼隱藏相簿? 1.進入小米手機的設定裡。 2、然後再點選隱私和保護。 3.在這裡再點選保護隱私。 4、點選保險箱。 5.最後在這裡就可以設置私密相簿。常見問題連接藍牙換輸入法主題更換出廠設定隱藏應用投影電視NFC開啟雙卡安裝啟動時間

    紅米Note13RPro怎麼調整字體大小? 紅米Note13RPro怎麼調整字體大小? May 07, 2024 pm 06:34 PM

    不要改變原內容的意思,微調內容,重寫內容,不要續寫紅米Note13RPro不僅性能出色,使用體驗更加出色,為了讓大家有更舒適的使用體驗,紅米Note13RPro配備了字體調整功能,讓用戶能夠調整自己的手機的字體。如果你想知道紅米Note13RPro怎麼調整字體大小,那就來看看吧。紅米Note13RPro怎麼調整字體大小? 1.開啟“設定”應用程式。 2.捲動到底部,選擇“顯示”。 3.點選“文字大小”。 4.在此畫面上,您可以拖曳滑桿調整字體大小或選擇預設字體大小。 5.調整完畢後,按「確定」保

    紅米Note13RPro怎麼連接電腦? 紅米Note13RPro怎麼連接電腦? May 09, 2024 pm 06:52 PM

    RedmiNote13RPro這款手機最近是非常火爆的,很多消費者都購買了這款手機,不過很多用戶是第一次使用這款手機所以不清楚紅米Note13RPro怎麼連接電腦,對此,小編在這裡為大家帶來了詳細的教學介紹。紅米Note13RPro怎麼連接電腦? 1.使用USB線將紅米手機連接到電腦的USB介面。 2.開啟手機設置,擊選項,將USB調試開啟。 3.在電腦上開啟裝置管理員,找到行動裝置選項。 4.右鍵點選行動裝置,選擇更新驅動程式,然後選擇自動搜尋更新的驅動程式。 5.如果電腦沒有自動搜尋到驅動程序,

    紅米Note13RPro怎麼關閉拍照聲音? 紅米Note13RPro怎麼關閉拍照聲音? May 02, 2024 pm 06:31 PM

    紅米Note13RPro的拍照功能非常好用,特別是在拍照的時候會模擬相機快門的聲音,不過這個功能在圖書館等一些安靜的場合會影響別人,所以很多用戶想知道紅米Note13RPro怎麼關閉拍照聲音,下面就讓小編來告訴你。紅米Note13RPro怎麼關閉拍照聲音? 1.第一種方法,首先需要開啟手機的設定。 2.然後在設定選單下找到系統應用程式。 3.緊接著我們在系統應用介面下找到相機選項。 4.最後,我們在相機介面下就可以設定相機聲音的關閉與否了,只需要將相機聲音右邊的開關關閉就可以了。 5.第二種方法,第一步,打開

    紅米Note13RPro怎麼擷取圖中的文字? 紅米Note13RPro怎麼擷取圖中的文字? May 08, 2024 pm 10:00 PM

    紅米Note13RPro手機在軟體功能上整合了多項智慧工具,其中,從圖片中快速準確地提取文字內容便是其中之一,下面小編將為大家介紹紅米Note13RPro如何提取圖片中的文字。紅米Note13RPro怎麼擷取圖中的文字?使用小米掃碼功能,打開手機的掃碼應用,點擊圖片圖標,選擇一張圖片,然後點擊右邊的「識別文字」選項,成功提取圖片中的文字。透過手機相簿操作。在手機相簿中找到需要提取文字的圖片,點擊圖片下方的“更多”,選擇“提取文字”,識別成功後,可以根據需要複製或保存文字。利用微信小程式。打開微

    《整個活吧》全關卡通關攻略大全 《整個活吧》全關卡通關攻略大全 May 07, 2024 pm 06:31 PM

    整個活吧是一款非常好玩的休閒解謎小遊戲,大家可以在多平台體驗!遊戲提供了無數精彩的關卡等待解鎖,每個關卡都充滿了新奇和挑戰,讓你體驗回答問題的有趣冒險,開啟全新的遊戲內容。那麼整個活吧全關卡怎麼通關呢?今天為大家帶來了《整個活吧》全關卡通關攻略大全分享,大家過關遇到問題可以來參考一下哦! 《整個活吧》全關卡通關攻略大全《整個活吧》全關卡通關攻略大全幫她守歲人鬼情未了幫小姐姐識別渣男狼外婆幫小女孩脫離危險戶外探險假裝看不見阿飄變回人形幫猩猩修成人形後座有人保持鎮定和女鬼週旋夜班出租車保持鎮定和女鬼週

    紅米Note13RPro怎麼設定流量顯示? 紅米Note13RPro怎麼設定流量顯示? May 02, 2024 pm 03:34 PM

    RedmiNote13RPro是一款備受廣大用戶喜愛的手機。這款手機提供了特別的方法來讓流量顯示在手機上,如果你還不知道RedmiNote13RPro怎麼設定顯示流量,那麼就跟著小編一起來了解一下吧。紅米Note13RPro怎麼設定流量顯示? 1、進入“設定”,點選“雙卡行動網路”。 2、下滑選擇「流量套餐設定」選項。 3.開啟「通知列顯示流量資訊」及「狀態列顯示當時網速」右側的功能開關。 4.設定成功後,下拉狀態列就可以看到即時網速及流量資訊的顯示了。常見問題連接藍牙換輸入法主題更換出廠設定隱藏應用投

    紅米Note13RPro怎麼開熱點? 紅米Note13RPro怎麼開熱點? May 03, 2024 pm 12:31 PM

    熱點功能是紅米Note13RPro上一個非常有用的功能,有了它使用者即使在戶外也可以使用一些需要連網才能使用的裝置。接下來,小編將詳細介紹紅米Note13RPro怎麼開熱點,讓大家都能學會使用這個強大的功能。紅米Note13RPro怎麼開熱點?首先在設定介面中,點選連接與共享進入。然後進入頁面,點選個人熱點。最後將便利WiFi熱點,點選開啟即可。常見問題連接藍牙換輸入法主題更換出廠設定隱藏應用投影電視NFC開啟雙卡安裝啟動時間