feat : 배치, 익스쿼리 미사용으로 제거

pull/2/head
Kurt92 5 months ago
parent 9865e6b31a
commit e7618fbb2e

@ -1,224 +0,0 @@
package go.kr.project.system.execquery.config;
import go.kr.project.system.execquery.exception.TransactionException;
import go.kr.project.system.execquery.model.TransactionInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
public class IsolatedTransactionManager {
private final DataSource queryDataSource;
private final Map<String, TransactionInfo> transactions = new ConcurrentHashMap<>();
private long transactionTimeout; // 트랜잭션 타임아웃 (밀리초)
public IsolatedTransactionManager(@Qualifier("dataSource") DataSource queryDataSource,
@Value("${query-executor.transaction.timeout-minutes:5}") int timeoutMinutes) {
this.queryDataSource = queryDataSource;
// yml에서 분 단위로 설정된 값을 밀리초로 변환
this.transactionTimeout = timeoutMinutes * 60 * 1000L; // 분 -> 밀리초 변환
log.info("트랜잭션 타임아웃 설정: {}분 ({}ms)", timeoutMinutes, this.transactionTimeout);
}
/**
* ID
*/
public String beginTransaction() throws SQLException {
String transactionId = UUID.randomUUID().toString();
String sessionId = getCurrentSessionId();
Connection conn = queryDataSource.getConnection();
conn.setAutoCommit(false);
TransactionInfo info = new TransactionInfo();
info.setConnection(conn);
info.setLastAccessTime(System.currentTimeMillis());
info.setCreationTime(System.currentTimeMillis());
info.setSessionId(sessionId);
transactions.put(transactionId, info);
log.debug("트랜잭션 시작: {}, 세션: {}", transactionId, sessionId);
return transactionId;
}
/**
* ID
*/
public Connection getConnection(String transactionId) throws SQLException {
if (transactionId == null || transactionId.isEmpty()) {
return beginNewConnection();
}
if (!transactions.containsKey(transactionId)) {
throw new TransactionException("존재하지 않는 트랜잭션 ID: " + transactionId);
}
TransactionInfo info = transactions.get(transactionId);
String currentSessionId = getCurrentSessionId();
// 세션 ID가 일치하는지 확인
if (!currentSessionId.equals(info.getSessionId())) {
throw new TransactionException("트랜잭션 접근 권한이 없습니다. 다른 세션에서 생성된 트랜잭션입니다.");
}
info.setLastAccessTime(System.currentTimeMillis());
return info.getConnection();
}
/**
* (SELECT )
*/
private Connection beginNewConnection() throws SQLException {
Connection conn = queryDataSource.getConnection();
conn.setAutoCommit(true);
return conn;
}
/**
*
*/
public void commitTransaction(String transactionId) throws SQLException {
if (!transactions.containsKey(transactionId)) {
throw new TransactionException("존재하지 않는 트랜잭션 ID: " + transactionId);
}
TransactionInfo info = transactions.get(transactionId);
String currentSessionId = getCurrentSessionId();
if (!currentSessionId.equals(info.getSessionId())) {
throw new TransactionException("트랜잭션 접근 권한이 없습니다. 다른 세션에서 생성된 트랜잭션입니다.");
}
try {
info.getConnection().commit();
log.debug("트랜잭션 커밋: {}", transactionId);
closeAndRemove(transactionId);
} catch (SQLException e) {
log.error("트랜잭션 커밋 중 오류 발생: {}", e.getMessage(), e);
throw e;
}
}
/**
*
*/
public void rollbackTransaction(String transactionId) throws SQLException {
if (!transactions.containsKey(transactionId)) {
throw new TransactionException("존재하지 않는 트랜잭션 ID: " + transactionId);
}
TransactionInfo info = transactions.get(transactionId);
String currentSessionId = getCurrentSessionId();
if (!currentSessionId.equals(info.getSessionId())) {
throw new TransactionException("트랜잭션 접근 권한이 없습니다. 다른 세션에서 생성된 트랜잭션입니다.");
}
try {
info.getConnection().rollback();
log.debug("트랜잭션 롤백: {}", transactionId);
closeAndRemove(transactionId);
} catch (SQLException e) {
log.error("트랜잭션 롤백 중 오류 발생: {}", e.getMessage(), e);
throw e;
}
}
/**
*
*/
private void closeAndRemove(String transactionId) {
TransactionInfo info = transactions.get(transactionId);
if (info != null) {
try {
info.getConnection().close();
} catch (SQLException e) {
log.error("커넥션 닫기 중 오류 발생: {}", e.getMessage(), e);
} finally {
transactions.remove(transactionId);
}
}
}
/**
* ID
*/
private String getCurrentSessionId() {
try {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attr.getRequest();
HttpSession session = request.getSession(true);
return session.getId();
} catch (Exception e) {
log.warn("세션 ID 가져오기 실패: {}", e.getMessage());
return "unknown-session";
}
}
/**
* (1 )
*/
@Scheduled(fixedRate = 60000)
public void cleanupIdleTransactions() {
long currentTime = System.currentTimeMillis();
transactions.entrySet().removeIf(entry -> {
TransactionInfo info = entry.getValue();
boolean isTimeout = (currentTime - info.getLastAccessTime() > transactionTimeout);
if (isTimeout) {
try {
info.getConnection().rollback();
info.getConnection().close();
log.info("유휴 트랜잭션 정리: {}, 세션: {}, 경과 시간: {}ms",
entry.getKey(),
info.getSessionId(),
currentTime - info.getCreationTime());
return true;
} catch (SQLException e) {
log.error("유휴 트랜잭션 정리 중 오류 발생: {}", e.getMessage(), e);
}
}
return false;
});
}
/**
*
*/
public void cleanupSessionTransactions(String sessionId) {
if (sessionId == null) return;
transactions.entrySet().removeIf(entry -> {
TransactionInfo info = entry.getValue();
if (sessionId.equals(info.getSessionId())) {
try {
info.getConnection().rollback();
info.getConnection().close();
log.info("세션 종료로 인한 트랜잭션 정리: {}", entry.getKey());
return true;
} catch (SQLException e) {
log.error("세션 트랜잭션 정리 중 오류 발생: {}", e.getMessage(), e);
}
}
return false;
});
}
}

@ -1,93 +0,0 @@
package go.kr.project.system.execquery.controller;
import egovframework.constant.TilesConstants;
import go.kr.project.system.execquery.model.QueryRequest;
import go.kr.project.system.execquery.model.QueryResponse;
import go.kr.project.system.execquery.service.DbQueryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@Slf4j
@RequiredArgsConstructor
@Controller
@RequestMapping("/db/exec")
public class DbQueryController {
private final DbQueryService dbQueryService;
/**
* <pre> : </pre>
* @param req
* @return String
* @author:
* @date: 2021. 9. 27.
*/
@GetMapping(value = "query.do")
public String query(HttpServletRequest req, Model model) {
return "system/db/exec" + TilesConstants.BASE;
}
@PostMapping("/queryexec.do")
public ResponseEntity<QueryResponse> executeQuery(
@RequestBody QueryRequest request,
HttpServletRequest httpRequest) {
try {
// Base64 인코딩된 쿼리가 있으면 디코딩
if (request.isBase64Encoded() && request.getQuery() != null) {
String base64Query = request.getQuery();
log.info("Base64 인코딩된 쿼리 수신: {}", base64Query);
// Base64 디코딩
byte[] decodedBytes = Base64.getDecoder().decode(base64Query);
String decodedQuery = new String(decodedBytes, StandardCharsets.UTF_8);
log.info("디코딩된 쿼리: {}", decodedQuery);
// 개별 쿼리를 받으므로 세미콜론 제거 로직을 수정
// 쿼리 끝의 세미콜론만 제거 (중간에 있는 세미콜론은 유지)
String cleanedQuery = decodedQuery.trim();
if (cleanedQuery.endsWith(";")) {
cleanedQuery = cleanedQuery.substring(0, cleanedQuery.length() - 1).trim();
}
request.setQuery(cleanedQuery);
}
// 세션 ID 추가
HttpSession session = httpRequest.getSession(true);
request.setSessionId(session.getId());
// SQL 쿼리 실행 전 로깅
log.info("쿼리 실행 요청: 타입={}, 트랜잭션ID={}, 세션ID={}",
request.getQueryType(), request.getTransactionId(), session.getId());
QueryResponse response = dbQueryService.executeQuery(request);
// 응답 로깅
log.info("쿼리 실행 결과: 성공={}, 행수={}, 트랜잭션ID={}",
response.isSuccess(), response.getRowsAffected(), response.getTransactionId());
return ResponseEntity.ok(response);
} catch (Exception e) {
log.error("쿼리 실행 중 오류 발생", e);
QueryResponse errorResponse = new QueryResponse();
errorResponse.setSuccess(false);
errorResponse.setMessage("쿼리 실행 중 오류: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
}
}
}

@ -1,13 +0,0 @@
package go.kr.project.system.execquery.exception;
public class TransactionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TransactionException(String message) {
super(message);
}
public TransactionException(String message, Throwable cause) {
super(message, cause);
}
}

@ -1,13 +0,0 @@
package go.kr.project.system.execquery.model;
import lombok.Data;
@Data
public class QueryRequest {
private String query;
private String queryType; // SELECT, INSERT, UPDATE, DELETE, COMMIT, ROLLBACK
private String transactionId;
private String sessionId;
private boolean isBase64Encoded = true; // 새로운 필드 추가
}

@ -1,13 +0,0 @@
package go.kr.project.system.execquery.model;
import lombok.Data;
@Data
public class QueryResponse {
private boolean success;
private Object result;
private String message;
private int rowsAffected;
private String transactionId;
private String queryType;
}

@ -1,13 +0,0 @@
package go.kr.project.system.execquery.model;
import lombok.Data;
import java.sql.Connection;
@Data
public class TransactionInfo {
private Connection connection;
private long lastAccessTime;
private String sessionId;
private long creationTime;
}

@ -1,328 +0,0 @@
package go.kr.project.system.execquery.service;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import go.kr.project.system.execquery.config.IsolatedTransactionManager;
import go.kr.project.system.execquery.exception.TransactionException;
import go.kr.project.system.execquery.model.QueryRequest;
import go.kr.project.system.execquery.model.QueryResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
@Slf4j
@RequiredArgsConstructor
@Service
public class DbQueryService {
private final IsolatedTransactionManager transactionManager;
// 결과 수 제한 상수 추가
private static final int MAX_RESULT_COUNT = 10000;
/**
* SELECT
*/
public QueryResponse executeSelect(QueryRequest request) {
QueryResponse response = new QueryResponse();
response.setQueryType("SELECT");
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// SELECT 쿼리인지 검증
String query = request.getQuery().toUpperCase();
if (containsDataModificationStatements(query)) {
response.setSuccess(false);
response.setMessage("SELECT 쿼리 타입으로 INSERT, UPDATE, DELETE 쿼리를 실행할 수 없습니다.");
return response;
}
conn = transactionManager.getConnection(request.getTransactionId());
// SELECT 쿼리는 읽기 전용으로 설정 (트랜잭션이 없는 경우에만)
if (request.getTransactionId() == null || request.getTransactionId().isEmpty()) {
conn.setReadOnly(true);
}
ps = conn.prepareStatement(request.getQuery());
rs = ps.executeQuery();
List<Map<String, Object>> resultList = new ArrayList<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
int rowCount = 0;
boolean resultLimited = false;
while (rs.next()) {
// 최대 결과 수 체크
if (rowCount >= MAX_RESULT_COUNT) {
resultLimited = true;
break;
}
Map<String, Object> row = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnLabel(i);
int columnType = metaData.getColumnType(i);
Object value = rs.getObject(i);
// DATE 타입인 경우
if (columnType == Types.DATE && value != null) {
Date dateValue = rs.getDate(i);
if (dateValue != null) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
value = dateFormat.format(dateValue);
}
}
// TIMESTAMP 또는 DATETIME 타입인 경우
else if ((columnType == Types.TIMESTAMP || columnType == Types.TIMESTAMP_WITH_TIMEZONE) && value != null) {
Timestamp timestampValue = rs.getTimestamp(i);
if (timestampValue != null) {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
value = dateTimeFormat.format(timestampValue);
}
}
row.put(columnName, value);
}
resultList.add(row);
rowCount++;
}
response.setSuccess(true);
response.setResult(resultList);
response.setRowsAffected(resultList.size());
// 결과가 제한되었을 경우 메시지 추가
if (resultLimited) {
response.setMessage("결과가 너무 많아 " + MAX_RESULT_COUNT + "건만 표시합니다.");
}
if (request.getTransactionId() != null && !request.getTransactionId().isEmpty()) {
response.setTransactionId(request.getTransactionId());
}
} catch (SQLException e) {
log.error("SELECT 쿼리 실행 중 오류: {}", e.getMessage(), e);
response.setSuccess(false);
response.setMessage("쿼리 실행 중 오류가 발생했습니다: " + e.getMessage());
if (request.getTransactionId() != null && !request.getTransactionId().isEmpty()) {
response.setTransactionId(request.getTransactionId());
}
} finally {
closeResources(rs, ps, conn, request.getTransactionId() != null);
}
return response;
}
/**
* (INSERT, UPDATE, DELETE)
*/
public QueryResponse executeUpdate(QueryRequest request) {
QueryResponse response = new QueryResponse();
response.setQueryType(request.getQueryType());
Connection conn = null;
PreparedStatement ps = null;
try {
// 트랜잭션ID가 없으면 새로 생성
if (request.getTransactionId() == null || request.getTransactionId().isEmpty()) {
String transactionId = transactionManager.beginTransaction();
request.setTransactionId(transactionId);
response.setTransactionId(transactionId);
} else {
response.setTransactionId(request.getTransactionId());
}
conn = transactionManager.getConnection(request.getTransactionId());
ps = conn.prepareStatement(request.getQuery());
int rowsAffected = ps.executeUpdate();
response.setSuccess(true);
response.setMessage("쿼리가 성공적으로 실행되었습니다. 변경사항은 커밋하기 전까지 임시 저장됩니다.");
response.setRowsAffected(rowsAffected);
} catch (SQLException e) {
log.error("{} 쿼리 실행 중 오류: {}", request.getQueryType(), e.getMessage(), e);
response.setSuccess(false);
response.setMessage("쿼리 실행 중 오류가 발생했습니다: " + e.getMessage());
response.setTransactionId(request.getTransactionId());
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
log.error("PreparedStatement 닫기 오류", e);
}
}
}
return response;
}
/**
*
*/
public QueryResponse executeCommit(QueryRequest request) {
QueryResponse response = new QueryResponse();
response.setQueryType("COMMIT");
try {
if (request.getTransactionId() == null || request.getTransactionId().isEmpty()) {
response.setSuccess(false);
response.setMessage("커밋할 트랜잭션 ID가 필요합니다.");
return response;
}
transactionManager.commitTransaction(request.getTransactionId());
response.setSuccess(true);
response.setMessage("트랜잭션이 성공적으로 커밋되었습니다.");
} catch (TransactionException e) {
log.error("트랜잭션 커밋 권한 오류: {}", e.getMessage(), e);
response.setSuccess(false);
response.setMessage(e.getMessage());
response.setTransactionId(request.getTransactionId());
} catch (SQLException e) {
log.error("트랜잭션 커밋 중 오류: {}", e.getMessage(), e);
response.setSuccess(false);
response.setMessage("트랜잭션 커밋 중 오류가 발생했습니다: " + e.getMessage());
response.setTransactionId(request.getTransactionId());
}
return response;
}
/**
*
*/
public QueryResponse executeRollback(QueryRequest request) {
QueryResponse response = new QueryResponse();
response.setQueryType("ROLLBACK");
try {
if (request.getTransactionId() == null || request.getTransactionId().isEmpty()) {
response.setSuccess(false);
response.setMessage("롤백할 트랜잭션 ID가 필요합니다.");
return response;
}
transactionManager.rollbackTransaction(request.getTransactionId());
response.setSuccess(true);
response.setMessage("트랜잭션이 성공적으로 롤백되었습니다.");
} catch (TransactionException e) {
log.error("트랜잭션 롤백 권한 오류: {}", e.getMessage(), e);
response.setSuccess(false);
response.setMessage(e.getMessage());
response.setTransactionId(request.getTransactionId());
} catch (SQLException e) {
log.error("트랜잭션 롤백 중 오류: {}", e.getMessage(), e);
response.setSuccess(false);
response.setMessage("트랜잭션 롤백 중 오류가 발생했습니다: " + e.getMessage());
response.setTransactionId(request.getTransactionId());
}
return response;
}
/**
*
*/
public QueryResponse executeQuery(QueryRequest request) {
String queryType = request.getQueryType().toUpperCase();
// ObjectMapper 생성 및 설정
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
// 요청 객체를 다시 파싱 (필요한 경우)
// 예: 요청 객체의 쿼리 문자열에 줄바꿈이 포함되어 있을 경우
String requestJson = null;
QueryRequest sanitizedRequest = null;
try {
requestJson = objectMapper.writeValueAsString(request);
sanitizedRequest = objectMapper.readValue(requestJson, QueryRequest.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
switch (queryType) {
case "SELECT":
return executeSelect(sanitizedRequest);
case "INSERT":
case "UPDATE":
case "DELETE":
return executeUpdate(sanitizedRequest);
case "COMMIT":
return executeCommit(request);
case "ROLLBACK":
return executeRollback(request);
default:
QueryResponse response = new QueryResponse();
response.setSuccess(false);
response.setMessage("지원하지 않는 쿼리 타입입니다. SELECT, INSERT, UPDATE, DELETE, COMMIT, ROLLBACK만 지원합니다.");
return response;
}
}
/**
* (INSERT, UPDATE, DELETE)
*/
private boolean containsDataModificationStatements(String query) {
// 정규식을 사용하여 INSERT, UPDATE, DELETE 키워드가 단어 경계에 있는지 확인
return query.matches("(?i).*\\bINSERT\\b.*") ||
query.matches("(?i).*\\bUPDATE\\b.*") ||
query.matches("(?i).*\\bDELETE\\b.*");
}
/**
*
*/
private void closeResources(ResultSet rs, PreparedStatement ps, Connection conn, boolean keepConnection) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.error("ResultSet 닫기 오류", e);
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
log.error("PreparedStatement 닫기 오류", e);
}
}
if (conn != null && !keepConnection) {
try {
// 연결을 닫기 전에 읽기 전용 모드를 해제
if (conn.isReadOnly()) {
conn.setReadOnly(false);
}
conn.close();
} catch (SQLException e) {
log.error("Connection 닫기 오류", e);
}
}
}
}

@ -1,177 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.BatchFileDataMapper">
<!-- 배치 파일 데이터 등록 -->
<insert id="insertBatchFileData" parameterType="BatchFileDataVO">
<selectKey keyProperty="fileDataId" resultType="String" order="BEFORE">
SELECT CONCAT('BFDT', LPAD(NEXTVAL(seq_batch_file_data_id), 16, '0'))
</selectKey>
INSERT INTO TB_BATCH_FILE_DATA (
FILE_DATA_ID,
FILE_NM,
LINE_NUMBER,
COLUMN1,
COLUMN2,
COLUMN3,
COLUMN4,
COLUMN5,
RAW_DATA,
PROCESS_STATUS,
ERROR_MESSAGE,
PROCESS_DTTM,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES (
#{fileDataId},
#{fileNm},
#{lineNumber},
#{column1},
#{column2},
#{column3},
#{column4},
#{column5},
#{rawData},
#{processStatus},
#{errorMessage},
#{processDttm},
NOW(),
#{rgtr},
NOW(),
#{mdfr}
)
</insert>
<!-- 배치 파일 데이터 수정 -->
<update id="updateBatchFileData" parameterType="BatchFileDataVO">
UPDATE TB_BATCH_FILE_DATA
SET
COLUMN1 = #{column1},
COLUMN2 = #{column2},
COLUMN3 = #{column3},
COLUMN4 = #{column4},
COLUMN5 = #{column5},
RAW_DATA = #{rawData},
PROCESS_STATUS = #{processStatus},
ERROR_MESSAGE = #{errorMessage},
PROCESS_DTTM = #{processDttm},
MDFCN_DTTM = NOW(),
MDFR = #{mdfr}
WHERE FILE_DATA_ID = #{fileDataId}
</update>
<!-- 배치 파일 데이터 삭제 -->
<delete id="deleteBatchFileData" parameterType="String">
DELETE FROM tb_batch_file_data
WHERE FILE_DATA_ID = #{fileDataId}
</delete>
<!-- 배치 파일 데이터 조회 -->
<select id="selectBatchFileData" parameterType="String" resultType="BatchFileDataVO">
SELECT
file_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data
WHERE file_data_id = #{fileDataId}
</select>
<!-- 배치 파일 데이터 총 개수 조회 -->
<select id="selectBatchFileDataTotalCount" parameterType="BatchFileDataVO" resultType="int">
SELECT COUNT(*)
FROM tb_batch_file_data
WHERE 1=1
<if test="searchFileNm != null and searchFileNm != ''">
AND file_nm LIKE CONCAT('%', #{searchFileNm}, '%')
</if>
<if test="searchProcessStatus != null and searchProcessStatus != ''">
AND process_status = #{searchProcessStatus}
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(process_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(process_dttm) &lt;= #{searchEndDate}
</if>
</select>
<!-- 배치 파일 데이터 목록 조회 -->
<select id="selectBatchFileDataList" parameterType="BatchFileDataVO" resultType="BatchFileDataVO">
SELECT
file_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data
WHERE 1=1
<if test="searchFileNm != null and searchFileNm != ''">
AND file_nm LIKE CONCAT('%', #{searchFileNm}, '%')
</if>
<if test="searchProcessStatus != null and searchProcessStatus != ''">
AND process_status = #{searchProcessStatus}
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(process_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(process_dttm) &lt;= #{searchEndDate}
</if>
ORDER BY process_dttm DESC, line_number ASC
<if test="pagingYn == 'Y'">
LIMIT #{startIndex}, #{recordCountPerPage}
</if>
</select>
<!-- 파일명으로 배치 파일 데이터 목록 조회 -->
<select id="selectBatchFileDataByFileNm" parameterType="String" resultType="BatchFileDataVO">
SELECT
file_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data
WHERE file_nm = #{fileNm}
ORDER BY line_number ASC
</select>
</mapper>

@ -1,165 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.BatchFileDataSuccessMapper">
<!-- 배치 파일 성공 데이터 등록 -->
<insert id="insertBatchFileDataSuccess" parameterType="BatchFileDataSuccessVO">
<selectKey keyProperty="successDataId" resultType="String" order="BEFORE">
SELECT CONCAT('BSDT', LPAD(NEXTVAL(seq_batch_file_data_success_id), 16, '0'))
</selectKey>
INSERT INTO tb_batch_file_data_success (
success_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES (
#{successDataId},
#{fileNm},
#{lineNumber},
#{column1},
#{column2},
#{column3},
#{column4},
#{column5},
#{rawData},
#{processDttm},
NOW(),
#{rgtr},
NOW(),
#{mdfr}
)
</insert>
<!-- 배치 파일 성공 데이터 수정 -->
<update id="updateBatchFileDataSuccess" parameterType="BatchFileDataSuccessVO">
UPDATE tb_batch_file_data_success
SET
column1 = #{column1},
column2 = #{column2},
column3 = #{column3},
column4 = #{column4},
column5 = #{column5},
raw_data = #{rawData},
process_dttm = #{processDttm},
MDFCN_DTTM = NOW(),
MDFR = #{mdfr}
WHERE success_data_id = #{successDataId}
</update>
<!-- 배치 파일 성공 데이터 삭제 -->
<delete id="deleteBatchFileDataSuccess" parameterType="String">
DELETE FROM tb_batch_file_data_success
WHERE success_data_id = #{successDataId}
</delete>
<!-- 배치 파일 성공 데이터 조회 -->
<select id="selectBatchFileDataSuccess" parameterType="String" resultType="BatchFileDataSuccessVO">
SELECT
success_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data_success
WHERE success_data_id = #{successDataId}
</select>
<!-- 배치 파일 성공 데이터 총 개수 조회 -->
<select id="selectBatchFileDataSuccessTotalCount" parameterType="BatchFileDataSuccessVO" resultType="int">
SELECT COUNT(*)
FROM tb_batch_file_data_success
WHERE 1=1
<if test="searchFileNm != null and searchFileNm != ''">
AND file_nm LIKE CONCAT('%', #{searchFileNm}, '%')
</if>
<if test="searchColumn1 != null and searchColumn1 != ''">
AND column1 LIKE CONCAT('%', #{searchColumn1}, '%')
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(process_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(process_dttm) &lt;= #{searchEndDate}
</if>
</select>
<!-- 배치 파일 성공 데이터 목록 조회 -->
<select id="selectBatchFileDataSuccessList" parameterType="BatchFileDataSuccessVO" resultType="BatchFileDataSuccessVO">
SELECT
success_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data_success
WHERE 1=1
<if test="searchFileNm != null and searchFileNm != ''">
AND file_nm LIKE CONCAT('%', #{searchFileNm}, '%')
</if>
<if test="searchColumn1 != null and searchColumn1 != ''">
AND column1 LIKE CONCAT('%', #{searchColumn1}, '%')
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(process_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(process_dttm) &lt;= #{searchEndDate}
</if>
ORDER BY process_dttm DESC, line_number ASC
<if test="pagingYn == 'Y'">
LIMIT #{startIndex}, #{recordCountPerPage}
</if>
</select>
<!-- 파일명으로 배치 파일 성공 데이터 목록 조회 -->
<select id="selectBatchFileDataSuccessByFileNm" parameterType="String" resultType="BatchFileDataSuccessVO">
SELECT
success_data_id,
file_nm,
line_number,
column1,
column2,
column3,
column4,
column5,
raw_data,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_data_success
WHERE file_nm = #{fileNm}
ORDER BY line_number ASC
</select>
</mapper>

@ -1,223 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.BatchFileRetryMapper">
<!-- 재처리 이력 등록 -->
<insert id="insertBatchFileRetry" parameterType="BatchFileRetryVO">
<selectKey keyProperty="retryId" resultType="String" order="BEFORE">
SELECT CONCAT('BFRT', LPAD(NEXTVAL(seq_batch_file_retry_id), 16, '0'))
</selectKey>
INSERT INTO tb_batch_file_retry (
retry_id,
original_file_nm,
retry_file_nm,
retry_cnt,
max_retry_cnt,
retry_status,
error_type,
error_message,
retry_dttm,
next_retry_dttm,
completed_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES (
#{retryId},
#{originalFileNm},
#{retryFileNm},
#{retryCnt},
#{maxRetryCnt},
#{retryStatus},
#{errorType},
#{errorMessage},
#{retryDttm},
#{nextRetryDttm},
#{completedDttm},
NOW(),
#{rgtr},
NOW(),
#{mdfr}
)
</insert>
<!-- 재처리 이력 수정 -->
<update id="updateBatchFileRetry" parameterType="BatchFileRetryVO">
UPDATE tb_batch_file_retry
SET retry_file_nm = #{retryFileNm},
retry_count = #{retryCount},
retry_status = #{retryStatus},
<if test = 'retryStatus == "SUCCESS"'>
error_type = null,
error_message = null,
</if>
<if test = 'retryStatus != "SUCCESS"'>
error_type = #{errorType},
error_message = #{errorMessage},
</if>
retry_dttm = #{retryDttm},
next_retry_dttm = #{nextRetryDttm},
completed_dttm = #{completedDttm},
MDFCN_DTTM = NOW(),
MDFR = #{mdfr}
WHERE retry_id = #{retryId}
</update>
<!-- 재처리 이력 삭제 -->
<delete id="deleteBatchFileRetry" parameterType="String">
DELETE FROM tb_batch_file_retry
WHERE retry_id = #{retryId}
</delete>
<!-- 재처리 이력 조회 -->
<select id="selectBatchFileRetry" parameterType="String" resultType="BatchFileRetryVO">
SELECT retry_id,
original_file_nm,
retry_file_nm,
retry_cnt,
max_retry_cnt,
retry_status,
error_type,
error_message,
retry_dttm,
next_retry_dttm,
completed_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_retry
WHERE retry_id = #{retryId}
</select>
<!-- 재처리 이력 목록 총 개수 조회 -->
<select id="selectBatchFileRetryListTotalCount" parameterType="BatchFileRetryVO" resultType="int">
SELECT COUNT(*)
FROM tb_batch_file_retry
<where>
<if test="originalFileNm != null and originalFileNm != ''">
AND original_file_nm LIKE CONCAT('%', #{originalFileNm}, '%')
</if>
<if test="retryStatus != null and retryStatus != ''">
AND retry_status = #{retryStatus}
</if>
<if test="errorType != null and errorType != ''">
AND error_type = #{errorType}
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(retry_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(retry_dttm) &lt;= #{searchEndDate}
</if>
</where>
</select>
<!-- 재처리 이력 목록 조회 -->
<select id="selectBatchFileRetryList" parameterType="BatchFileRetryVO" resultType="BatchFileRetryVO">
SELECT retry_id,
original_file_nm,
retry_file_nm,
retry_cnt,
max_retry_cnt,
retry_status,
error_type,
error_message,
retry_dttm,
next_retry_dttm,
completed_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_retry
<where>
<if test="originalFileNm != null and originalFileNm != ''">
AND original_file_nm LIKE CONCAT('%', #{originalFileNm}, '%')
</if>
<if test="retryStatus != null and retryStatus != ''">
AND retry_status = #{retryStatus}
</if>
<if test="errorType != null and errorType != ''">
AND error_type = #{errorType}
</if>
<if test="searchStartDate != null and searchStartDate != ''">
AND DATE(retry_dttm) >= #{searchStartDate}
</if>
<if test="searchEndDate != null and searchEndDate != ''">
AND DATE(retry_dttm) &lt;= #{searchEndDate}
</if>
</where>
ORDER BY retry_dttm DESC
<if test="pagingYn == 'Y'">
LIMIT #{recordCountPerPage} OFFSET #{firstIndex}
</if>
</select>
<!-- 원본 파일명으로 재처리 이력 조회 -->
<select id="selectBatchFileRetryByOriginalFileNm" parameterType="String" resultType="BatchFileRetryVO">
SELECT retry_id,
original_file_nm,
retry_file_nm,
retry_cnt,
max_retry_cnt,
retry_status,
error_type,
error_message,
retry_dttm,
next_retry_dttm,
completed_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_retry
WHERE original_file_nm = #{originalFileNm}
ORDER BY retry_dttm DESC
</select>
<!-- 재처리 대상 파일 목록 조회 -->
<select id="selectRetryTargetFiles" resultType="BatchFileRetryVO">
SELECT retry_id,
original_file_nm,
retry_file_nm,
retry_cnt,
max_retry_cnt,
retry_status,
error_type,
error_message,
retry_dttm,
next_retry_dttm,
completed_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_file_retry
WHERE retry_status = 'PENDING'
AND retry_cnt &lt; max_retry_cnt
AND (next_retry_dttm IS NULL OR next_retry_dttm &lt;= NOW())
ORDER BY retry_dttm ASC
</select>
<!-- 재처리 상태 업데이트 -->
<update id="updateRetryStatus">
UPDATE tb_batch_file_retry
SET retry_status = #{retryStatus},
MDFCN_DTTM = NOW(),
MDFR = 'BATCH_SYSTEM'
WHERE retry_id = #{retryId}
</update>
<!-- 재처리 횟수 증가 -->
<update id="incrementRetryCnt">
UPDATE tb_batch_file_retry
SET retry_cnt = retry_cnt + 1,
retry_dttm = NOW(),
MDFCN_DTTM = NOW(),
MDFR = 'BATCH_SYSTEM'
WHERE retry_id = #{retryId}
</update>
</mapper>

@ -1,363 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.BatchJobMapper">
<!-- 배치 작업 정보 등록 -->
<insert id="insertBatchJobInfo" parameterType="BatchJobInfoVO">
INSERT INTO TB_BATCH_JOB_INFO (
JOB_ID,
JOB_NM,
JOB_GROUP,
JOB_CLASS,
CRON_EXPRESSION,
JOB_DC,
STATUS_CD,
LAST_EXECUTION_ID,
REG_DTTM,
MDFCN_DTTM
) VALUES (
#{jobId},
#{jobNm},
#{jobGroup},
#{jobClass},
#{cronExpression},
#{jobDc},
#{statusCd},
#{lastExecutionId},
NOW(),
NOW()
)
</insert>
<!-- 배치 작업 정보 수정 -->
<update id="updateBatchJobInfo" parameterType="BatchJobInfoVO">
UPDATE TB_BATCH_JOB_INFO
SET
JOB_NM = #{jobNm},
JOB_GROUP = #{jobGroup},
JOB_CLASS = #{jobClass},
CRON_EXPRESSION = #{cronExpression},
JOB_DC = #{jobDc},
STATUS_CD = #{statusCd},
MDFCN_DTTM = NOW()
WHERE
JOB_ID = #{jobId}
</update>
<!-- 배치 작업 정보 삭제 -->
<delete id="deleteBatchJobInfo" parameterType="String">
DELETE FROM TB_BATCH_JOB_INFO
WHERE JOB_ID = #{jobId}
</delete>
<!-- 배치 작업 정보 조회 -->
<select id="selectBatchJobInfo" parameterType="String" resultType="BatchJobInfoVO">
SELECT
A.JOB_ID,
A.JOB_NM,
A.JOB_GROUP,
A.JOB_CLASS,
A.CRON_EXPRESSION,
A.JOB_DC,
A.STATUS_CD,
B.CD_NM as statusNm,
A.LAST_EXECUTION_ID,
A.REG_DTTM,
A.MDFCN_DTTM
FROM
TB_BATCH_JOB_INFO A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_JOB_INFO_STATUS_CD'
WHERE
A.JOB_ID = #{jobId}
</select>
<!-- 배치 작업 정보를 이름과 그룹으로 조회 -->
<select id="selectBatchJobInfoByNmAndGroup" resultType="BatchJobInfoVO">
SELECT
A.JOB_ID,
A.JOB_NM,
A.JOB_GROUP,
A.JOB_CLASS,
A.CRON_EXPRESSION,
A.JOB_DC,
A.STATUS_CD,
B.CD_NM as statusNm,
A.LAST_EXECUTION_ID,
A.REG_DTTM,
A.MDFCN_DTTM
FROM
TB_BATCH_JOB_INFO A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_JOB_INFO_STATUS_CD'
WHERE
A.JOB_NM = #{jobNm}
AND A.JOB_GROUP = #{jobGroup}
</select>
<!-- 모든 배치 작업 정보 조회 -->
<select id="selectBatchJobInfoList" resultType="BatchJobInfoVO" parameterType="BatchJobExecutionVO">
SELECT
A.JOB_ID,
A.JOB_NM,
A.JOB_GROUP,
A.JOB_CLASS,
A.CRON_EXPRESSION,
A.JOB_DC,
A.STATUS_CD,
B.CD_NM as statusNm,
A.LAST_EXECUTION_ID,
A.REG_DTTM,
A.MDFCN_DTTM
FROM
TB_BATCH_JOB_INFO A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_JOB_INFO_STATUS_CD'
WHERE 1=1
<if test="searchStatusCd != null and searchStatusCd != ''">
AND A.STATUS_CD = #{searchStatusCd}
</if>
ORDER BY
A.REG_DTTM DESC
</select>
<!-- 배치 작업 실행 결과 등록 -->
<insert id="insertBatchJobExecution" parameterType="BatchJobExecutionVO">
INSERT INTO TB_BATCH_JOB_EXECUTION (
EXECUTION_ID,
JOB_NM,
JOB_GROUP,
START_DTTM,
END_DTTM,
STATUS_CD,
EXIT_CD,
EXIT_MESSAGE,
SERVER_INFO,
REG_DTTM
) VALUES (
#{executionId},
#{jobNm},
#{jobGroup},
#{startDttm},
#{endDttm},
#{statusCd},
#{exitCd},
#{exitMessage},
#{serverInfo},
NOW()
)
</insert>
<!-- 배치 작업 실행 결과 수정 -->
<update id="updateBatchJobExecution" parameterType="BatchJobExecutionVO">
UPDATE TB_BATCH_JOB_EXECUTION
SET
END_DTTM = #{endDttm},
STATUS_CD = #{statusCd},
EXIT_CD = #{exitCd},
EXIT_MESSAGE = #{exitMessage},
SERVER_INFO = #{serverInfo}
WHERE
EXECUTION_ID = #{executionId}
</update>
<!-- 배치 작업 실행 결과 조회 -->
<select id="selectBatchJobExecution" parameterType="String" resultType="BatchJobExecutionVO">
SELECT
A.EXECUTION_ID,
A.JOB_NM,
A.JOB_GROUP,
A.START_DTTM,
A.END_DTTM,
A.STATUS_CD,
B.CD_NM as statusNm,
A.EXIT_CD,
C.CD_NM as exitCdNm,
A.EXIT_MESSAGE,
A.SERVER_INFO,
A.REG_DTTM
FROM
TB_BATCH_JOB_EXECUTION A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_EXEC_STATUS_CD'
LEFT JOIN
tb_cd_detail C ON A.EXIT_CD = C.CD_ID AND C.CD_GROUP_ID = 'BATCH_EXIT_CD'
WHERE
A.EXECUTION_ID = #{executionId}
</select>
<!-- 배치 작업의 실행 결과 목록 조회 -->
<select id="selectBatchJobExecutionTotalCount" resultType="int">
SELECT COUNT(*)
FROM
TB_BATCH_JOB_EXECUTION A
WHERE
A.JOB_NM = #{jobNm}
AND A.JOB_GROUP = #{jobGroup}
<if test="searchStatusCd != null and searchStatusCd != ''">
AND A.STATUS_CD = #{searchStatusCd}
</if>
<if test="searchExitCd != null and searchExitCd != ''">
<choose>
<when test="searchExitCd == 'UNKNOWN'">
AND (A.EXIT_CD = #{searchExitCd} OR A.EXIT_CD IS NULL)
</when>
<otherwise>
AND A.EXIT_CD = #{searchExitCd}
</otherwise>
</choose>
</if>
<if test='searchStartDt != null and searchEndDt != null'>
AND A.START_DTTM BETWEEN STR_TO_DATE(CONCAT(#{searchStartDt},' 00:00:00'), '%Y-%m-%d %H:%i:%s')
AND STR_TO_DATE(CONCAT(#{searchEndDt},' 23:59:59'), '%Y-%m-%d %H:%i:%s')
</if>
</select>
<!-- 배치 작업의 실행 결과 목록 조회 -->
<select id="selectBatchJobExecutionList" resultType="BatchJobExecutionVO">
SELECT
A.EXECUTION_ID,
A.JOB_NM,
A.JOB_GROUP,
A.START_DTTM,
A.END_DTTM,
A.STATUS_CD,
B.CD_NM as STATUS_NM,
A.EXIT_CD,
C.CD_NM as EXIT_CD_NM,
A.EXIT_MESSAGE,
A.SERVER_INFO,
A.REG_DTTM
FROM
TB_BATCH_JOB_EXECUTION A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_EXEC_STATUS_CD'
LEFT JOIN
tb_cd_detail C ON A.EXIT_CD = C.CD_ID AND C.CD_GROUP_ID = 'BATCH_EXIT_CD'
WHERE
A.JOB_NM = #{jobNm}
AND A.JOB_GROUP = #{jobGroup}
<if test="searchStatusCd != null and searchStatusCd != ''">
AND A.STATUS_CD = #{searchStatusCd}
</if>
<if test="searchExitCd != null and searchExitCd != ''">
<choose>
<when test="searchExitCd == 'UNKNOWN'">
AND (A.EXIT_CD = #{searchExitCd} OR A.EXIT_CD IS NULL)
</when>
<otherwise>
AND A.EXIT_CD = #{searchExitCd}
</otherwise>
</choose>
</if>
<if test='searchStartDt != null and searchEndDt != null'>
AND A.START_DTTM BETWEEN STR_TO_DATE(CONCAT(#{searchStartDt},' 00:00:00'), '%Y-%m-%d %H:%i:%s')
AND STR_TO_DATE(CONCAT(#{searchEndDt},' 23:59:59'), '%Y-%m-%d %H:%i:%s')
</if>
ORDER BY
A.START_DTTM DESC
<if test="pagingYn != null and pagingYn.toString() == 'Y'.toString()">
LIMIT #{startIndex}, #{perPage}
</if>
</select>
<!-- 배치 작업의 마지막 실행 결과 조회 -->
<select id="selectLastBatchJobExecution" resultType="BatchJobExecutionVO">
SELECT
A.EXECUTION_ID,
A.JOB_NM,
A.JOB_GROUP,
A.START_DTTM,
A.END_DTTM,
A.STATUS_CD,
B.CD_NM as statusNm,
A.EXIT_CD,
C.CD_NM as exitCdNm,
A.EXIT_MESSAGE,
A.SERVER_INFO,
A.REG_DTTM
FROM
TB_BATCH_JOB_EXECUTION A
LEFT JOIN
tb_cd_detail B ON A.STATUS_CD = B.CD_ID AND B.CD_GROUP_ID = 'BATCH_EXEC_STATUS_CD'
LEFT JOIN
tb_cd_detail C ON A.EXIT_CD = C.CD_ID AND C.CD_GROUP_ID = 'BATCH_EXIT_CD'
WHERE
A.JOB_NM = #{jobNm}
AND A.JOB_GROUP = #{jobGroup}
ORDER BY
A.START_DTTM DESC
LIMIT 1
</select>
<!-- 배치 작업 상태 업데이트 -->
<update id="updateBatchJobStatus">
UPDATE TB_BATCH_JOB_INFO
SET
STATUS_CD = #{statusCd},
MDFCN_DTTM = NOW()
WHERE
JOB_ID = #{jobId}
</update>
<!-- 배치 작업의 마지막 실행 ID 업데이트 -->
<update id="updateBatchJobLastExecution">
UPDATE TB_BATCH_JOB_INFO
SET
LAST_EXECUTION_ID = #{executionId},
MDFCN_DTTM = NOW()
WHERE
JOB_ID = #{jobId}
</update>
<!-- 배치 작업 실행 로그 등록 -->
<insert id="insertBatchJobLog">
INSERT INTO TB_BATCH_JOB_LOG (
LOG_ID,
EXECUTION_ID,
LOG_DTTM,
LOG_LEVEL,
LOG_MESSAGE,
REG_DTTM
) VALUES (
CONCAT('BJLG', LPAD(NEXTVAL(seq_batch_job_log_id), 16, '0')),
#{executionId},
NOW(),
#{logLevel},
#{logMessage},
NOW()
)
</insert>
<!-- 배치 작업 실행 로그 목록 조회 -->
<select id="selectBatchJobLogList" parameterType="String" resultType="BatchJobLogVO">
SELECT
LOG_ID,
EXECUTION_ID,
LOG_DTTM,
LOG_LEVEL,
LOG_MESSAGE,
REG_DTTM
FROM
TB_BATCH_JOB_LOG
WHERE
EXECUTION_ID = #{executionId}
<if test="searchLogLevel != null and searchLogLevel != ''">
AND LOG_LEVEL = #{searchLogLevel}
</if>
ORDER BY
LOG_DTTM ASC
</select>
<!-- 최근 48시간 내 실패한 배치 작업 목록 조회 -->
<select id="selectRecentlyFailedJobs" resultType="BatchJobInfoVO">
SELECT DISTINCT
A.JOB_NM,
A.JOB_GROUP
FROM
TB_BATCH_JOB_EXECUTION A
WHERE
(A.EXIT_CD != 'COMPLETED')
AND A.START_DTTM >= DATE_SUB(NOW(), INTERVAL 48 HOUR)
</select>
</mapper>

@ -1,211 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.ZipFileDetailLogMapper">
<!-- ZIP 파일 처리 상세 로그 ID 생성 -->
<select id="generateZipFileDetailLogId" resultType="String">
SELECT CONCAT('ZFDL', LPAD(NEXTVAL(seq_batch_zip_file_detail_log_id), 16, '0'))
</select>
<!-- ZIP 파일 처리 상세 로그 등록 -->
<insert id="insertZipFileDetailLog" parameterType="ZipFileDetailLogVO">
<selectKey keyProperty="detailLogId" resultType="String" order="BEFORE">
SELECT CONCAT('ZFDL', LPAD(NEXTVAL(seq_batch_zip_file_detail_log_id), 16, '0'))
</selectKey>
INSERT INTO tb_batch_zip_file_detail_log (
detail_log_id,
log_id,
file_nm,
file_path,
file_size,
file_type,
image_yn,
corrupted_yn,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES (
#{detailLogId},
#{logId},
#{fileNm},
#{filePath},
#{fileSize},
#{fileType},
#{imageYn},
#{corruptedYn},
#{processStatus},
#{errorMessage},
#{processDttm},
NOW(),
#{rgtr},
NOW(),
#{mdfr}
)
</insert>
<!-- ZIP 파일 처리 상세 로그 목록 일괄 등록 -->
<insert id="insertZipFileDetailLogList" parameterType="java.util.List">
INSERT INTO tb_batch_zip_file_detail_log (
detail_log_id,
log_id,
file_nm,
file_path,
file_size,
file_type,
image_yn,
corrupted_yn,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES
<foreach collection="list" item="item" separator=",">
(
CONCAT('ZFDL', LPAD(NEXTVAL(seq_batch_zip_file_detail_log_id), 16, '0')),
#{item.logId},
#{item.fileNm},
#{item.filePath},
#{item.fileSize},
#{item.fileType},
#{item.imageYn},
#{item.corruptedYn},
#{item.processStatus},
#{item.errorMessage},
#{item.processDttm},
NOW(),
#{item.rgtr},
NOW(),
#{item.mdfr}
)
</foreach>
</insert>
<!-- ZIP 파일 처리 상세 로그 삭제 -->
<delete id="deleteZipFileDetailLog" parameterType="String">
DELETE FROM tb_batch_zip_file_detail_log
WHERE detail_log_id = #{detailLogId}
</delete>
<!-- 로그 ID로 ZIP 파일 처리 상세 로그 삭제 -->
<delete id="deleteZipFileDetailLogByLogId" parameterType="String">
DELETE FROM tb_batch_zip_file_detail_log
WHERE log_id = #{logId}
</delete>
<!-- ZIP 파일 처리 상세 로그 조회 -->
<select id="selectZipFileDetailLog" parameterType="String" resultType="ZipFileDetailLogVO">
SELECT
detail_log_id,
log_id,
file_nm,
file_path,
file_size,
file_type,
image_yn,
corrupted_yn,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_zip_file_detail_log
WHERE detail_log_id = #{detailLogId}
</select>
<!-- 로그 ID로 ZIP 파일 처리 상세 로그 목록 조회 -->
<select id="selectZipFileDetailLogListByLogId" parameterType="String" resultType="ZipFileDetailLogVO">
SELECT
detail_log_id,
log_id,
file_nm,
file_path,
file_size,
file_type,
image_yn,
corrupted_yn,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_zip_file_detail_log
WHERE log_id = #{logId}
ORDER BY process_dttm ASC
</select>
<!-- ZIP 파일 처리 상세 로그 목록 총 개수 조회 -->
<select id="selectZipFileDetailLogListTotalCount" parameterType="ZipFileDetailLogVO" resultType="int">
SELECT COUNT(*)
FROM tb_batch_zip_file_detail_log
WHERE 1=1
<if test="logId != null and logId != ''">
AND log_id = #{logId}
</if>
<if test="fileNm != null and fileNm != ''">
AND file_nm LIKE CONCAT('%', #{fileNm}, '%')
</if>
<if test="processStatus != null and processStatus != ''">
AND process_status = #{processStatus}
</if>
<if test="imageYn != null and imageYn != ''">
AND image_yn = #{imageYn}
</if>
<if test="corruptedYn != null and corruptedYn != ''">
AND corrupted_yn = #{corruptedYn}
</if>
</select>
<!-- ZIP 파일 처리 상세 로그 목록 조회 -->
<select id="selectZipFileDetailLogList" parameterType="ZipFileDetailLogVO" resultType="ZipFileDetailLogVO">
SELECT
detail_log_id,
log_id,
file_nm,
file_path,
file_size,
file_type,
image_yn,
corrupted_yn,
process_status,
error_message,
process_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
FROM tb_batch_zip_file_detail_log
WHERE 1=1
<if test="logId != null and logId != ''">
AND log_id = #{logId}
</if>
<if test="fileNm != null and fileNm != ''">
AND file_nm LIKE CONCAT('%', #{fileNm}, '%')
</if>
<if test="processStatus != null and processStatus != ''">
AND process_status = #{processStatus}
</if>
<if test="imageYn != null and imageYn != ''">
AND image_yn = #{imageYn}
</if>
<if test="corruptedYn != null and corruptedYn != ''">
AND corrupted_yn = #{corruptedYn}
</if>
ORDER BY process_dttm ASC
<if test="pagingYn == 'Y'">
LIMIT #{startIndex}, #{recordCountPerPage}
</if>
</select>
</mapper>

@ -1,186 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="go.kr.project.batch.mapper.ZipFileProcessLogMapper">
<!-- ZIP 파일 처리 로그 ID 생성 -->
<select id="generateZipFileProcessLogId" resultType="String">
SELECT CONCAT('ZPFL', LPAD(NEXTVAL(seq_batch_zip_file_process_log_id), 16, '0'))
</select>
<!-- ZIP 파일 처리 로그 등록 -->
<insert id="insertZipFileProcessLog" parameterType="ZipFileProcessLogVO">
INSERT INTO tb_batch_zip_file_process_log (
log_id,
zip_file_nm,
zip_file_path,
extract_path,
archive_path,
total_file_cnt,
success_file_cnt,
error_file_cnt,
image_file_cnt,
non_image_file_cnt,
corrupted_file_cnt,
process_status,
error_message,
start_dttm,
end_dttm,
REG_DTTM,
RGTR,
MDFCN_DTTM,
MDFR
) VALUES (
#{logId},
#{zipFileNm},
#{zipFilePath},
#{extractPath},
#{archivePath},
#{totalFileCnt},
#{successFileCnt},
#{errorFileCnt},
#{imageFileCnt},
#{nonImageFileCnt},
#{corruptedFileCnt},
#{processStatus},
#{errorMessage},
#{startDttm},
#{endDttm},
NOW(),
#{rgtr},
NOW(),
#{mdfr}
)
</insert>
<!-- ZIP 파일 처리 로그 수정 -->
<update id="updateZipFileProcessLog" parameterType="ZipFileProcessLogVO">
UPDATE tb_batch_zip_file_process_log
SET
extract_path = #{extractPath},
archive_path = #{archivePath},
total_file_cnt = #{totalFileCnt},
success_file_cnt = #{successFileCnt},
error_file_cnt = #{errorFileCnt},
image_file_cnt = #{imageFileCnt},
non_image_file_cnt = #{nonImageFileCnt},
corrupted_file_cnt = #{corruptedFileCnt},
process_status = #{processStatus},
error_message = #{errorMessage},
end_dttm = #{endDttm},
MDFCN_DTTM = NOW(),
MDFR = #{mdfr}
WHERE log_id = #{logId}
</update>
<!-- ZIP 파일 처리 로그 삭제 -->
<delete id="deleteZipFileProcessLog" parameterType="String">
DELETE FROM tb_batch_zip_file_process_log
WHERE log_id = #{logId}
</delete>
<!-- ZIP 파일 처리 로그 조회 -->
<select id="selectZipFileProcessLog" parameterType="String" resultType="ZipFileProcessLogVO">
SELECT
log_id AS logId,
zip_file_nm AS zipFileNm,
zip_file_path AS zipFilePath,
extract_path AS extractPath,
archive_path AS archivePath,
total_file_cnt AS totalFileCnt,
success_file_cnt AS successFileCnt,
error_file_cnt AS errorFileCnt,
image_file_cnt AS imageFileCnt,
non_image_file_cnt AS nonImageFileCnt,
corrupted_file_cnt AS corruptedFileCnt,
process_status AS processStatus,
error_message AS errorMessage,
start_dttm AS startDttm,
end_dttm AS endDttm,
REG_DTTM AS regDttm,
RGTR AS rgtr,
MDFCN_DTTM AS mdfcnDttm,
MDFR AS mdfr
FROM tb_batch_zip_file_process_log
WHERE log_id = #{logId}
</select>
<!-- ZIP 파일 처리 로그 목록 총 개수 조회 -->
<select id="selectZipFileProcessLogListTotalCount" parameterType="ZipFileProcessLogVO" resultType="int">
SELECT COUNT(*)
FROM tb_batch_zip_file_process_log
WHERE 1=1
<if test="zipFileNm != null and zipFileNm != ''">
AND zip_file_nm LIKE CONCAT('%', #{zipFileNm}, '%')
</if>
<if test="processStatus != null and processStatus != ''">
AND process_status = #{processStatus}
</if>
</select>
<!-- ZIP 파일 처리 로그 목록 조회 -->
<select id="selectZipFileProcessLogList" parameterType="ZipFileProcessLogVO" resultType="ZipFileProcessLogVO">
SELECT
log_id AS logId,
zip_file_nm AS zipFileNm,
zip_file_path AS zipFilePath,
extract_path AS extractPath,
archive_path AS archivePath,
total_file_cnt AS totalFileCnt,
success_file_cnt AS successFileCnt,
error_file_cnt AS errorFileCnt,
image_file_cnt AS imageFileCnt,
non_image_file_cnt AS nonImageFileCnt,
corrupted_file_cnt AS corruptedFileCnt,
process_status AS processStatus,
error_message AS errorMessage,
start_dttm AS startDttm,
end_dttm AS endDttm,
REG_DTTM AS regDttm,
RGTR AS rgtr,
MDFCN_DTTM AS mdfcnDttm,
MDFR AS mdfr
FROM tb_batch_zip_file_process_log
WHERE 1=1
<if test="zipFileNm != null and zipFileNm != ''">
AND zip_file_nm LIKE CONCAT('%', #{zipFileNm}, '%')
</if>
<if test="processStatus != null and processStatus != ''">
AND process_status = #{processStatus}
</if>
ORDER BY start_dttm DESC
<if test="pagingYn == 'Y'">
LIMIT #{startIndex}, #{recordCountPerPage}
</if>
</select>
<!-- 처리 중인 ZIP 파일 로그 조회 -->
<select id="selectProcessingZipFileLog" parameterType="String" resultType="ZipFileProcessLogVO">
SELECT
log_id AS logId,
zip_file_nm AS zipFileNm,
zip_file_path AS zipFilePath,
extract_path AS extractPath,
archive_path AS archivePath,
total_file_cnt AS totalFileCnt,
success_file_cnt AS successFileCnt,
error_file_cnt AS errorFileCnt,
image_file_cnt AS imageFileCnt,
non_image_file_cnt AS nonImageFileCnt,
corrupted_file_cnt AS corruptedFileCnt,
process_status AS processStatus,
error_message AS errorMessage,
start_dttm AS startDttm,
end_dttm AS endDttm,
REG_DTTM AS regDttm,
RGTR AS rgtr,
MDFCN_DTTM AS mdfcnDttm,
MDFR AS mdfr
FROM tb_batch_zip_file_process_log
WHERE zip_file_nm = #{zipFileNm}
AND process_status = 'PROCESSING'
ORDER BY start_dttm DESC
LIMIT 1
</select>
</mapper>
Loading…
Cancel
Save