JDBC Batch는 프로젝트와 별개로 작업하고 실행을 할 수 있어서 수정사항 발생시 바로바로 적용을 할 수 있다는 점이 운영하는 측에서는 편한 작업이 될 수 있습니다.  그러나 Batch job의 개수가 많아지거나 Table 사이즈가 크거나 작업의 우선 순위가 있어야 하는 경우 등의 상황에서는 다른 방법과 병행해서 사용하는게 개인적으로는 좋았던 것 같습니다.

 

 

 

오늘 기록해 놓으려는 소스는 SELECT 문을 사용해 key값의 데이터가 기존에 입력 되어있는지 확인하고 존재하면 UPDATE, 없으면 INSERT하는 단순 작업입니다.

 

1. DB 접속

먼저 DB 접속을 정의합니다.

 

Connection conn = null;
Class.forName("org.mariadb.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mariadb://127.0.0.1:3306", "db_id","db_passwd");
conn.setAutoCommit(false);

 

Driver는 사용하는 DB에 맞게 수정하면 됩니다.

 

2. Select 사용

 

기존에 입력된 데이터가 있는지 확인을 하기위해 함수를 하나 만들어서 결과를 리턴 받습니다.

int iCnt = getInsertCnt(conn, yesterday);

DB 접속 정보와 날짜를 파라미터로 데이터가 있는지 조회하는 쿼리입니다.

 

PreparedStatement pstmt = null;
int nCnt = 0;
ResultSet rs = null;
                    
try {
 
           StringBuilder sql = new StringBuilder();
           sql.append("SELECT count(*) AS CNT FROM test.statistics WHERE INSERT_DT = ?");
          
           pstmt = conn.prepareStatement(sql.toString());
           pstmt.setString(1, yesterDay);
                        
           rs = pstmt.executeQuery();
           while(rs.next()) {
               nCnt =  rs.getInt(1);
               System.out.println("=== CNT : " + rs + "/" + nCnt);
           }
           rs.close();
           pstmt.close();
}

 

PreparedStatement : 쿼리를 높은 효율성으로 반복적으로 사용하기위한 저장 객체.

ResultSet : SQL 쿼리를 실행한 결과를 저장하는 객체.

nCnt : SELECT 결과의 개수를 저장하려고 만든 변수입니다.

 

쿼리 생성시 사용하는 변수를 물음표(?)로 표시하고 값을 대입해서 쿼리를 완성하게 됩니다.

변수가 변경되면 쿼리는 수정하지 않고 변수 값만 수정해주면 반복해서 쿼리를 사용할 수 있게됩니다.

물음표에 해당하는 값을 대입하는데 사용되는 메소드는 아래처럼 정수, 실수, 문자등을 구분해서 대입하게 됩니다.

 

 

public void setInt(int index, int value)
public void setString(int index, String value)
public void setFloat(int index, float value)
public void setDouble(int index, double value)

 

index는 물음표의 순번으로 첫번째 물음표는 1이 됩니다.

 

쿼리를 실행하는 메소드는 여러 종류가 있는데 여기서는 SELECT 결과를 ResultSet에 담아야 하기때문에 리턴 값이 ResultSet인 메소드 executeQuery()를 선택해서 사용했습니다.

 

좀더 자세한 PreparedStatement 관련 메소드는 아래 링크를 참조하면 도움이 됩니다.

https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html

 

JDBC는 업무 로직이 복잡하면 어려워지는거고 실제 사용법은 간단합니다.  SELECT문 하나만으로 필요한 내용 설명은 거의 설명이 되는군요.

 

 

3. Insert / update

 

Insert문도 PreparedStatement 와 변수 대입을 위한 setString()을 사용합니다.

PreparedStatement pstmt = null;
                    
                     try {
                               
                    StringBuilder sql = new StringBuilder();
                    sql.append("INSERT INTO test.statistics (");
                    sql.append("  INSERT_DT");
                    sql.append(", VISIT_CNT");
                    sql.append(", PAGE_VIEW_CNT");
                    sql.append(", INST_DT");
                    sql.append(", INST_ID");
                    sql.append(") VALUES (");
                    sql.append(" ?");
                    sql.append(", (select 1 from dual)");
                    sql.append(", (select 2 from dual)");
                    sql.append(", date_format(now(), '%Y%m%d%H%i%s')");
                    sql.append(", 'tester'");
                    sql.append(")");
                   
                    pstmt = conn.prepareStatement(sql.toString());
                    pstmt.setString(1, yesterDay);
 

 

Select에서는 쿼리 실행을 위해 pstmt.executeQuery()를 사용하고 InsertUpdate에서는 addBatch()executeBatch()을 사용했습니다.

addBatch()는 쿼리를 바로 실행하지 않고 쿼리 구문을 메모리에 올려두었다가, 실행 명령(executeBatch)이 있으면 한번에 DB쪽으로 쿼리를 보내어 처리를 하게 됩니다.  , 한 번의 SQL 수행으로 대량의 로우를 동시에 insert / update / delete를 진행할 수 있어 대용량 처리를 하는데 적합한 방법입니다.

여기서는 달랑 하나 처리했는데 동일한 작업을 진행하려면 loop 문을 이용해서 작업을 하면 됩니다.

 

간단히 설명이 끝났습니다.

 

아래 소스를 보면 좀더 파악이 쉬우리라 생각하며 소스를 첨부합니다.

 

 

package com.example.demo.test;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
 
public class Job {
 
           public static void main(String[] args) {
                     
                     Connection conn = null;
 
               try {
                Class.forName("org.mariadb.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mariadb://127.0.0.1:3306", "root","will99");
                conn.setAutoCommit(false);
               
                String yesterday = getYesterday();
               
               
                      int iCnt = getInsertCnt(conn, yesterday);
               
                      if(iCnt < 1) {
                                 System.out.println("======  insert ==================");
                       insertData(conn, yesterday);
                      } else {
                                 System.out.println("======  update ==================");
                         updateData(conn, yesterday);
                      }
                      
                      conn.close();
                 
               } catch (Exception e) {
               
                  e.printStackTrace();
               } finally {
                if(conn != null) {
                 try {
                      conn.close();
                 } catch (Exception e) {}
                }
               }
           }
          
           private static int getInsertCnt(Connection conn, String yesterDay) {
                     PreparedStatement pstmt = null;
                     int nCnt = 0;
                     ResultSet rs = null;
                    
                     try {
                               
                                StringBuilder sql = new StringBuilder();
                         sql.append("SELECT count(*) AS CNT FROM test.statistics WHERE INSERT_DT = ?");
          
                         pstmt = conn.prepareStatement(sql.toString());
                         pstmt.setString(1, yesterDay);
                        
                         rs = pstmt.executeQuery();
                         while(rs.next()) {
                              nCnt =  rs.getInt(1);
                                    System.out.println("=== CNT : " + rs + "/" + nCnt);
                         }
                         rs.close();
                         pstmt.close();
 
              
                     } catch (Exception e) {
                      
                    e.printStackTrace();
                 } finally {
                      if(pstmt != null) {
                                 try {
                                 pstmt.close();
                                 } catch (Exception e) {}
                       }
        }
 
                     return nCnt;
           }
          
           private static void insertData(Connection conn, String yesterDay) {
                     PreparedStatement pstmt = null;
                    
                     try {
                               
                    StringBuilder sql = new StringBuilder();
                    sql.append("INSERT INTO test.statistics (");
                    sql.append("  INSERT_DT");
                    sql.append(", VISIT_CNT");
                    sql.append(", PAGE_VIEW_CNT");
                    sql.append(", INST_DT");
                    sql.append(", INST_ID");
                    sql.append(") VALUES (");
                    sql.append(" ?");
                    sql.append(", (select 1 from dual)");
                    sql.append(", (select 2 from dual)");
                    sql.append(", date_format(now(), '%Y%m%d%H%i%s')");
                    sql.append(", 'tester'");
                    sql.append(")");
                   
                    pstmt = conn.prepareStatement(sql.toString());
                    pstmt.setString(1, yesterDay);
                   
                    pstmt.addBatch();
                   
                    pstmt.clearParameters();
 
                    pstmt.executeBatch();
                   
                    pstmt.clearBatch();
                   
                    conn.commit();
                   
                    pstmt.close();
                  
                 } catch (Exception e) {
                      
                    e.printStackTrace();
                 } finally {
                      if(pstmt != null) {
                                 try {
                                 pstmt.close();
                                 } catch (Exception e) {}
                      }
                 }
           }
          
           private static void updateData(Connection conn, String yesterDay) {
                     PreparedStatement pstmt = null;
                    
                     try {
                               
                    StringBuilder sql = new StringBuilder();
                    sql.append("UPDATE test.statistics SET ");
                    sql.append("VISIT_CNT = (select 1 from dual)");
                    sql.append(", PAGE_VIEW_CNT = (select 1 from dual)");
                    sql.append(", UPDT_DT = date_format(now(), '%Y%m%d%H%i%s')");
                    sql.append(", UPDT_ID = 'tester'");
                    sql.append("where INSERT_DT = ?");
                   
                    pstmt = conn.prepareStatement(sql.toString());
                    pstmt.setString(1, yesterDay);
 
                    pstmt.addBatch();
                   
                    pstmt.clearParameters();
 
                    pstmt.executeBatch();
                   
                    pstmt.clearBatch();
                   
                    conn.commit();
                   
                    pstmt.close();
                  
                 } catch (Exception e) {
                      
                    e.printStackTrace();
                 } finally {
                      if(pstmt != null) {
                                 try {
                                 pstmt.close();
                                 } catch (Exception e) {}
                      }
                 }
           }
          
           private static String getYesterday() {
                     Date today = new Date();
                     SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                     String fmDate = sdf.format(today);
                     System.out.println("=== today : " + fmDate);
                    
                     Calendar cal = Calendar.getInstance();
                     cal.setTime(today);
                    
                     cal.add(Calendar.DATE, -1);
                     String fmDate2 = sdf.format(cal.getTime());
                     System.out.println("=== yesterday : " + fmDate2);
                    
                     return fmDate2;
           }
 
}

 

 - copy coding -

 

오라클의 Job Schedule과 동일하게 MariaDB에서도 Procedure가 있다면 별도의 언어를 사용하여 배치 프로그램을 생성하지 않고 MariaDB 이벤트 스케줄러를 사용하여 배치 처리를 할 수 있습니다.

 

Procedure를 사용해야 하기 때문에 JDBC 방식처럼 복잡한 작업이 동반되는 업무에는 적합하지 않고 단순히 DB들을 이용하여 작업하는 경우에는 작업 속도가 빠릅니다.

 

먼저 Event Scheduler를 사용하려면 DB에 기능이 활성화 되어있는지 쿼리를 이용하여 확인을 해야합니다.

 

SHOW VARIABLES WHERE VARIABLE_NAME = 'event_scheduler';

 

 

 

만약 위에 보이는 것처럼 OFF 상태라면 다음 쿼리로 활성화시켜줍니다.

 

SET GLOBAL event_scheduler = ON;

 

다시 한번 쿼리가 잘 적용되어 활성화 되었는지 확인합니다.

 

SHOW VARIABLES WHERE VARIABLE_NAME = 'event_scheduler';

 

 

 

이상 없이 적용 되었네요.

 

이제 DBEvent를 생성합니다.

쿼리는 아래와 같이 CREATE 명령을 사용하며 마지막에 실행되어야 하는 Procedure를 호출합니다.

 

CREATE EVENT EV_STATISTIC
    ON SCHEDULE every 1 MINUTE
    STARTS '2023-11-01 00:05:00'
    COMMENT '매분 1 이벤트가 실행된다.'
    DO
      call SP_STATISTICS(null);

 

테스트를 위해 1분에 한번씩 작동하도록 하였는데(every 1 MINUTE)

반복 주기는 아래와 같이 다양하게 선택해서 설정이 가능 합니다.

 

{YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

 

여기서 하나를 선택해서 반복 주기를 설정할 수 있습다.

 

이벤트 생성이 잘 되었는지 아래 명령을 이용하여 확인해봅니다.

 

SHOW EVENTS;

 

 

 

이벤트가 잘 생성 되었습니다.

 

만약 이벤트를 삭제하려면 Table 삭제와 비슷한 명령어를 사용합니다.

 

DROP EVENT EV_STATISTIC;

 

DB Tool을 이용하여 Event를 찾아보면 아래처럼 확인이 가능 합니다.

저는 DBeaver 사용중 입니다.

 

 

 

Interval Field 부분을 DAY로 변경하고 Comment를 수정하면 매일 1회 작동하는 배치로 변경이 가능 합니다.

 

- copy coding -

 

예전에는 자주 사용하는 문서를 USB는 가지고 다녀야 해서 귀찮아 메일로 보내놓고 사용했었는데 이제는 클라우드에 무료로 저장공간을 제공하는 회사가 많아져서 편리하게 사용하고 있습니다.구글에서 제공하는 드라이브는 웹에서 사용할 수도 있지만 프로그램을 설치하면 내 컴퓨터의 저장공간처럼 파일 탐색기를 이용하여 사용이 가능합니다.

구글 드라이브를 파일 탐색기에 연결하고 windows batch 파일을 생성해서 자동으로 파일을 백업 하고 윈도우도 종료하도록 하는 프로그램을 만들어 보려고 합니다.

 

작업 순서는

 

1. PC용 드라이브 파일 설치

2. Windows Batch파일 생성

3. 테스트

 

아래 설명을 읽어보기 귀찮으면 바로 다운로드 링크를 클릭 합니다.

https://dl.google.com/drive-file-stream/GoogleDriveSetup.exe

 

 

 

1. PC용 드라이브 파일 설치

 

먼저 PC용 드라이브를 다운로드 받기위해 구글 드라이브 메인화면에 접속합니다.

 

https://www.google.com/intl/ko_KR/drive/

 

구글 드라이브 메인 화면에서 하단으로 죽 내려가면 맨 아래쪽에

 

요런 화면이 나오는데 여기서 [Mac/PC용 드라이브]를 선택 합니다.

 

그러면 바로 다운로드가 되는게 아니고 다운로드 페이지로 이동을 하고요

 

https://www.google.com/intl/ko/drive/download/

 

 

다운로드 페이지에서 [데스크톱용 Drive 다운로드] 버튼을 클릭합니다.

아래 링크가 파일 다운로드 링크 입니다.

 

https://dl.google.com/drive-file-stream/GoogleDriveSetup.exe

 

다운받은 파일을 실행해서 설치를 진행 합니다.

 

 

바탕화면 바로가기를 사용하지 않을거면 체크를 해제하고 [설치] 버튼을 클릭해서 진행합니다.

 

 

잠시 후 설치가 완료되면 [닫기] 버튼으로 닫아주고

 

 

다른 창이 하나 뜨는데 여기서 [브라우저에서 로그인]을 클릭 합니다.

 

 

 

어떤 구글 계정을 사용해서 작업하려는지 선택하는 것으로 계정을 하나 클릭 합니다.

 

 

설명을 한번 읽어보시고 [로그인]을 클릭 합니다.

 

 

 

창을 닫으라는데 안닫아도 되고요.

 

파일 탐색기를 열어보면

 

 

Google Drive가 연결되어 있는걸 볼 수 있습니다.

 

 

예전에 테스트해본 문서들이 보이는 군요.  구글 드라이브도 파일 탐색기에서 일반 디스크와 동일하게 사용이 가능 합니다.

 

 

[드라이브]를 선택하면

 

 

[내 드라이브] 메뉴에서 파일 탐색기에서 본 것과 같은 파일들을 볼 수 있습니다.

 

 

2. Windows Batch파일 생성

 

이제 Windows에서 구글 드라이브로 백업 하는 배치 파일을 만들어 봅니다.

기능은 컴퓨터 작업을 완료하고 배치 파일을 실행해 주면 수정된 파일만 백업을 하고 윈도우를 자동 종료하는 기능 입니다.

그냥 정해진 시간이 되면 자동 백업하게 하려면 스캐줄러에 등록 합니다.

 

배치 파일 내용은 다음과 같습니다.

 

@Echo Off
 
mkdir "G:\내 드라이브\databackup\연습1"
mkdir "G:\내 드라이브\databackup\연습2"
 
robocopy D:\temp\연습1 "G:\내 드라이브\databackup\연습1"
robocopy D:\temp\연습2 "G:\내 드라이브\databackup\연습2"
 
shutdown -s -t 0

 

mkdir는 구글 드라이브에 폴더를 생성하는 명령입니다.

robocopy는 파일을 백업위치에 복사 하는 명령입니다.

shutdown은 시스템을 종료 합니다.

 

배치파일의 작동을 보면 먼저 복사할 위치에 폴더를 생성합니다(폴더가 있으면 생성안함).

robocopy명령으로 복사를 하는데 처음에는 모두 복사하고 다음부터는 변경파일만 복사합니다.

 

robocopy의 자세한 옵션은 콘솔에서 찾아볼 수 있습니다.

>명령어/?  이렇게 명령어에 슬래쉬와 무름표를 하면 사용법 설명을 볼 수 있습니다.

 

 

배치 파일을 만들었으니 저장 합니다.

 

배치 파일을 저장할때에는 확장자는 bat으로 하고 인코딩을 ANSI로 해야 한글을 인식하게 됩니다. 안그러면 오류나면서 복사가 되지 않습니다.

 

 

3. 테스트

 

테스트는 컴퓨터를 매번 종료하고 켜야하니 rem을 이용해서 종료는 주석처리 해줍니다.

rem shutdown -s -t 0

그리고 나중에 실제 사용할 때는 rem을 삭제하고 저장합니다.

 

 

배치파일을 클릭해서 실행하면 구글 드라이브에 파일이 복사 됩니다.

 

 

만일 폴더내에 파일이 많다면 처음 복사하는 시간이 좀 소요 됩니다.

이제 원본 문서를 하나 수정하고 다시 배치를 실행해 봅니다.

 

수정한 첫번째 파일이 복사 되었습니다.

배치파일을 클릭하지 않고 명령 프롬프트에서 실행해보면서 명령 창에서의 로그를 보겠습니다.

 

D:\temp>
D:\temp>backup_배치
하위 디렉터리 또는 파일 G:\내 드라이브\databackup\연습1이(가) 이미 있습니다.
하위 디렉터리 또는 파일 G:\내 드라이브\databackup\연습2이(가) 이미 있습니다.
 
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows용 견고한 파일 복사
-------------------------------------------------------------------------------
 
  시작됨: 2022 5 16일 월요일 오후 5:18:36
        원본 : D:\temp\연습1\
        대상 = G:\내 드라이브\databackup\연습1\
 
        파일 : *.*
 
        옵션 : *.* /DCOPY:DA /COPY:DAT /R:1000000 /W:30
 
------------------------------------------------------------------------------
 
                           2    D:\temp\연습1\
100%          최근                     7        새 텍스트 문서1.txt
 
------------------------------------------------------------------------------
 
                  전체       복사됨      건너 뜀       불일치        실패        추가
    디렉터리 :         1         0         1         0         0         0
         파일 :         2         1         1         0         0         0
       바이트 :         7         7         0         0         0         0
      시간 :   0:00:00   0:00:00                       0:00:00   0:00:00
 
 
      속도 :                 134 바이트/
      속도 :               0.007 메가바이트/
   종료됨: 2022 5 16일 월요일 오후 5:18:36
 
 
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows용 견고한 파일 복사
-------------------------------------------------------------------------------
 
  시작됨: 2022 5 16일 월요일 오후 5:18:36
        원본 : D:\temp\연습2\
        대상 = G:\내 드라이브\databackup\연습2\
 
        파일 : *.*
 
        옵션 : *.* /DCOPY:DA /COPY:DAT /R:1000000 /W:30
 
------------------------------------------------------------------------------
 
                           2    D:\temp\연습2\
 
------------------------------------------------------------------------------
 
                  전체       복사됨      건너 뜀       불일치        실패        추가
    디렉터리 :         1         0         1         0         0         0
         파일 :         2         0         2         0         0         0
     바이트 :    10.0 k         0    10.0 k         0         0         0
      시간 :   0:00:00   0:00:00                       0:00:00   0:00:00
   종료됨: 2022 5 16일 월요일 오후 5:18:36
 
 
D:\temp>

 

로그가 좀 길고 복잡해 보이기는 하지만 붉은색으로 된 부분을 보면

- 폴더들은 모두 있으니 건너 띄고

- 연습1 폴더의 두개 파일 중 하나만 수정되어 복사하였고

- 연습2 폴더의 두개 파일은 파일은 복사하지 않았다.

이런 내용 입니다.

 

백업 받으려고 기다리지 않고 그냥 배치 파일만 실행시켜 놓고 퇴근하면 종료가 되니 저는 편할것 같습니다.

 

- copy coding -


예전에 Quartz를 이용해서 작업할 때 보다는 @Scheduled annotation을 사용하면 배치 작업을 무척 쉽게 만들 수 있습니다.


spring boot Scheduler @Scheduled batch


얼마나 간단하고 쉬운지 한번 만들어 보겠습니다.


spring boot Scheduler @Scheduled batch


먼저 프로젝트를 하나 생성 합니다.


spring boot Scheduler @Scheduled batch


프로젝트 이름을 대충 적어주고


spring boot Scheduler @Scheduled batch


 

화면을 만들건 아니지만 일단 Web을 추가해서 생성 합니다.

 

이제 설정을 해줍니다.


Application 메인 파일을 열고

package com.copycoding.batch;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.scheduling.annotation.EnableScheduling;

 

@SpringBootApplication

@EnableScheduling

public class BatchApplication {

 

        public static void main(String[] args) {

               SpringApplication.run(BatchApplication.class, args);

        }

}

 

@EnableScheduling 어노테이션을 추가해 줍니다.

 

그리고 실제 스케쥴 작업할 class 파일을 만듭니다.

 

package com.copycoding.batch;

 

import java.time.LocalDateTime;

 

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;

 

@Component

public class ScheduleTask {

 

@Scheduled(fixedDelay = 2000)

public void task1() {

        System.out.println("The current date (1) : " + LocalDateTime.now());

}

       

@Scheduled(fixedDelayString = "${spring.task.fixedDelay}")

public void task2() {

        System.out.println("The current date (2) : " + LocalDateTime.now());

}}

 

중요한건 class 파일에 @Component를 설정해야 합니다이렇게 두개의 어노테이션을 적어주기만 하면 설정은 끝입니다.

이제 메소드를 만들고 @Scheduled를 이용해서 메소드의 작동 시간을 입력하고 코딩을 해줍니다위에 있는 프로그램을 실행하면


spring boot Scheduler @Scheduled batch


 

이런식으로 결과를 얻을 수 있습니다.  annotation만으로 쉽게 배치 작업이 완료 됩니다.

 

@Scheduled() 어노테이션에 들어가는 설정들을 정리해 보았습니다.

 

fixedDelay

@Scheduled(fixedDelay = 1000)

이전 작업이 종료된 후 설정시간(밀리터리세컨드) 이후에 다시 시작

fixedDelayString

@Scheduled(fixedDelay = “1000”)

fixedDelay와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

fixedRate

@Scheduled(fixedRate = 1000)

설정된 시간마다 시작을 한다. 즉 이전 작업이 종료되지 않아도 시작.

fixedRateString

@Scheduled(fixedRateString = “1000”)

fixedRate와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

initialDelay

@Scheduled(fixedRate = 5000, initialDelay = 3000)

프로그램이 시작하자마자 작업하는게 아닌 시작을 설정된 시간만큼 지연하여 작동을 시작 한다.(예제는 3초 후 부터 5초 간격으로 작업)

initialDelayString

@Scheduled(fixedRate = 5000, initialDelay = “3000”)

initialDelay와 동일 하고 지연시간(the delay in milliseconds)을 문자로 입력

cron

@Scheduled(cron = "* * * * * *")

첫번째 부터 위치별 설정 값은

(0-59)

(0-59)

시간(0-23)

(1-31)

(1-12)

요일(0-7)

zone

@Scheduled(cron = "0 0 14 * * *" , zone = "Asia/Seoul")

미설정시 local 시간대를 사용한다.

oracle에서 제공하는 문서를 참조하여 입력 한다.

https://docs.oracle.com/cd/B13866_04/webconf.904/b10877/timezone.htm

 

- copy coding -


1

+ Recent posts