refactor: 동기화 현황 화면 노출 테이블 목록 정리 (#11) (#13)

This commit is contained in:
HYOJIN 2026-03-25 10:58:19 +09:00
부모 d55fba7226
커밋 88a8e9c8a9
8개의 변경된 파일10개의 추가작업 그리고 117개의 파일을 삭제

파일 보기

@ -11,6 +11,7 @@
- abandon/stale 실행 관리 엔드포인트 구현 (#7)
### 변경
- 동기화 현황 노출 테이블 목록 정리: ship-001/ship-002 제거, source-target 키 매핑 정리 (#11)
- BaseSyncReader 추출: 49개 Reader 공통 로직 통합, 1 chunk = 1 job_execution_id 보장
- chunk 경계 제어를 GroupByExecutionIdPolicy에서 Reader 자체 제어로 변경
- BatchWriteListener: SQL을 실행 시점에 생성하여 SOURCE_SCHEMA null 문제 해결

파일 보기

@ -13,9 +13,6 @@ public class TableMetaInfo {
*/
// Ship Tables
@Value("${app.batch.source-schema.tables.ship-001}")
public String sourceShipData;
@Value("${app.batch.source-schema.tables.ship-002}")
public String sourceShipDetailData;
@ -158,10 +155,10 @@ public class TableMetaInfo {
@Value("${app.batch.source-schema.tables.risk-compliance-001}")
public String sourceRisk;
@Value("${app.batch.source-schema.tables.risk-compliance-002}")
@Value("${app.batch.source-schema.tables.risk-compliance-003}")
public String sourceCompliance;
@Value("${app.batch.source-schema.tables.risk-compliance-003}")
@Value("${app.batch.source-schema.tables.risk-compliance-006}")
public String sourceTbCompanyComplianceInfo;
@ -172,11 +169,8 @@ public class TableMetaInfo {
*/
// Ship Tables
@Value("${app.batch.target-schema.tables.ship-001}")
public String targetTbShipInfoMst;
@Value("${app.batch.target-schema.tables.ship-002}")
public String targetTbShipMainInfo;
public String targetTbShipInfoMst;
@Value("${app.batch.target-schema.tables.ship-003}")
public String targetTbShipAddInfo;

파일 보기

@ -142,59 +142,6 @@ public class ShipDataSql {
""".formatted(TARGET_SCHEMA, targetTable);
}
public static String getShipMainInfoUpsertSql(String targetTable) {
return """
INSERT INTO %s.%s (
crt_dt, creatr_id,
imo_no, mmsi_no, ship_nm, clsgn_no, country_nm,
ship_reg_hrbr, clfic_asctn_nm, ship_knd_lv_five, ship_knd_dtl_lv_five,
ship_build_yy, shpyrd_nm, ship_whlnth, ship_molbth, ship_depth, ship_draft,
ship_total_ton, dwt, cntnr_units, svc_crspd, main_engine_fom,
ship_status, ship_operator, ship_country_cd, ship_knd_lv_two, cargo_type,
last_mdfcn_dt
)
VALUES (
CURRENT_TIMESTAMP, 'SYSTEM',
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
?
)
ON CONFLICT (imo_no)
DO UPDATE SET
mdfcn_dt = CURRENT_TIMESTAMP,
mdfr_id = 'SYSTEM',
mmsi_no = EXCLUDED.mmsi_no,
ship_nm = EXCLUDED.ship_nm,
clsgn_no = EXCLUDED.clsgn_no,
country_nm = EXCLUDED.country_nm,
ship_reg_hrbr = EXCLUDED.ship_reg_hrbr,
clfic_asctn_nm = EXCLUDED.clfic_asctn_nm,
ship_knd_lv_five = EXCLUDED.ship_knd_lv_five,
ship_knd_dtl_lv_five = EXCLUDED.ship_knd_dtl_lv_five,
ship_build_yy = EXCLUDED.ship_build_yy,
shpyrd_nm = EXCLUDED.shpyrd_nm,
ship_whlnth = EXCLUDED.ship_whlnth,
ship_molbth = EXCLUDED.ship_molbth,
ship_depth = EXCLUDED.ship_depth,
ship_draft = EXCLUDED.ship_draft,
ship_total_ton = EXCLUDED.ship_total_ton,
dwt = EXCLUDED.dwt,
cntnr_units = EXCLUDED.cntnr_units,
svc_crspd = EXCLUDED.svc_crspd,
main_engine_fom = EXCLUDED.main_engine_fom,
ship_status = EXCLUDED.ship_status,
ship_operator = EXCLUDED.ship_operator,
ship_country_cd = EXCLUDED.ship_country_cd,
ship_knd_lv_two = EXCLUDED.ship_knd_lv_two,
cargo_type = EXCLUDED.cargo_type,
last_mdfcn_dt = EXCLUDED.last_mdfcn_dt;
""".formatted(TARGET_SCHEMA, targetTable);
}
public static String getShipAddInfoUpsertSql(String targetTable) {
return """
INSERT INTO %s.%s (

파일 보기

@ -35,7 +35,6 @@ import java.util.List;
*/
public interface ShipRepository {
void saveShipInfoMst(List<ShipInfoMstEntity> shipInfoMstEntityList);
void saveShipMainInfo(List<ShipInfoMstEntity> shipInfoMstEntityList);
void saveShipAddInfo(List<ShipAddInfoEntity> shipAddInfoEntityList);
void saveBareboatCharterHistory(List<BareboatCharterHistoryEntity> bareboatCharterHistoryEntityList);
void saveCallsignAndMmsiHistory(List<CallsignAndMmsiHistoryEntity> callsignAndMmsiHistoryEntityList);

파일 보기

@ -96,23 +96,6 @@ public class ShipRepositoryImpl extends MultiDataSourceJdbcRepository<ShipInfoMs
});
}
@Override
public void saveShipMainInfo(List<ShipInfoMstEntity> shipInfoMstEntityList) {
String core20Sql = ShipDataSql.getShipMainInfoUpsertSql(tableMetaInfo.targetTbShipMainInfo);
if (shipInfoMstEntityList == null || shipInfoMstEntityList.isEmpty()) {
return;
}
batchJdbcTemplate.batchUpdate(core20Sql, shipInfoMstEntityList, shipInfoMstEntityList.size(),
(ps, entity) -> {
try {
bindShipMainInfo(ps, (ShipInfoMstEntity) entity);
} catch (Exception e) {
log.error("배치 삽입 파라미터 설정 실패", e);
throw new RuntimeException(e);
}
});
}
public void bindShipInfoMst(PreparedStatement pstmt, ShipInfoMstEntity entity) throws Exception {
int idx = 1;
pstmt.setString(idx++, entity.getDatasetVer());
@ -201,36 +184,6 @@ public class ShipRepositoryImpl extends MultiDataSourceJdbcRepository<ShipInfoMs
pstmt.setString(idx++, entity.getLastMdfcnDt());
}
public void bindShipMainInfo(PreparedStatement pstmt, ShipInfoMstEntity entity) throws Exception {
int idx = 1;
pstmt.setString(idx++, entity.getImoNo());
pstmt.setString(idx++, entity.getMmsiNo());
pstmt.setString(idx++, entity.getShipNm());
pstmt.setString(idx++, entity.getClsgnNo());
pstmt.setString(idx++, entity.getShipNtnlty());
pstmt.setString(idx++, entity.getLoadPort());
pstmt.setString(idx++, entity.getClfic());
pstmt.setString(idx++, entity.getShipTypeLvFive());
pstmt.setString(idx++, entity.getShipTypeLvFiveDtldType());
pstmt.setString(idx++, entity.getBuildYy());
pstmt.setString(idx++, entity.getShpyrd());
pstmt.setObject(idx++, entity.getWhlnthLoa(), Types.DOUBLE);
pstmt.setObject(idx++, entity.getFormnBreadth(), Types.DOUBLE);
pstmt.setObject(idx++, entity.getDepth(), Types.DOUBLE);
pstmt.setObject(idx++, entity.getDraft(), Types.DOUBLE);
pstmt.setString(idx++, entity.getGt());
pstmt.setString(idx++, entity.getDwt());
pstmt.setString(idx++, entity.getTeuCnt());
pstmt.setObject(idx++, entity.getSvcSpd(), Types.DOUBLE);
pstmt.setString(idx++, entity.getMainEngineType());
pstmt.setString(idx++, entity.getShipStatus());
pstmt.setString(idx++, entity.getOperator());
pstmt.setString(idx++, entity.getNtnltyCd());
pstmt.setString(idx++, entity.getShipTypeLvTwo());
pstmt.setString(idx++, entity.getShipTypeLvThr());
pstmt.setString(idx++, entity.getLastMdfcnDt());
}
@Override
public void saveShipAddInfo(List<ShipAddInfoEntity> shipAddInfoEntityList) {
String sql = ShipDataSql.getShipAddInfoUpsertSql(tableMetaInfo.targetTbShipAddInfo);

파일 보기

@ -22,6 +22,5 @@ public class ShipDataWriter extends BaseChunkedWriter<ShipInfoMstEntity> {
return;
}
shipRepository.saveShipInfoMst(items); // 선박_정보_마스터 [ID: S&P-SHIP-001]
shipRepository.saveShipMainInfo(items); // 선박_주요_정보 [ID: S&P-SHIP-002]
}
}

파일 보기

@ -70,11 +70,13 @@ public class SyncStatusService {
ExecutorService executor = Executors.newFixedThreadPool(
Math.min(sourceTables.size(), 10));
// source와 target 양쪽 모두 매핑된 테이블만 조회
List<CompletableFuture<SyncTableStatus>> futures = sourceTables.entrySet().stream()
.filter(entry -> targetTables.containsKey(entry.getKey()))
.map(entry -> CompletableFuture.supplyAsync(() -> {
String tableKey = entry.getKey();
String sourceTable = entry.getValue();
String targetTable = targetTables.getOrDefault(tableKey, "");
String targetTable = targetTables.get(tableKey);
try {
return queryTableStatus(tableKey, sourceTable, targetTable);

파일 보기

@ -107,7 +107,6 @@ app:
source-schema:
name: std_snp_data
tables:
ship-001: tb_ship_default_info
ship-002: tb_ship_info_mst
ship-003: tb_ship_add_info
ship-004: tb_ship_bbctr_hstry
@ -153,13 +152,12 @@ app:
code-001: tb_ship_type_cd
code-002: tb_ship_country_cd
risk-compliance-001: tb_ship_risk_info
risk-compliance-002: tb_ship_compliance_info
risk-compliance-003: tb_company_compliance_info
risk-compliance-003: tb_ship_compliance_info
risk-compliance-006: tb_company_compliance_info
target-schema:
name: std_snp_svc
tables:
ship-001: tb_ship_info_mst
ship-002: tb_ship_main_info
ship-002: tb_ship_info_mst
ship-003: tb_ship_add_info
ship-004: tb_ship_bbctr_hstry
ship-005: tb_ship_idntf_info_hstry