실무에서 insert 로직을 작성하다 보면 이런 고민을 하게 된다.
“어차피 값 몇 개만 바꿔서 한 번 더 insert 하는 건데
객체를 새로 만들지 않고 재사용해도 되지 않을까?”
결론부터 말하면 insert에서 객체 재사용은 피하는 게 맞다.
특히 이력성·동의성 데이터라면 더더욱 그렇다.
아래는 하나의 요청에서 두 종류의 동의 데이터를 저장하는 상황을 단순화한 예시다.
먼저 기본 동의를 저장하고, 조건에 따라 추가 동의를 한 번 더 저장한다.
Agreement agre = new Agreement();
// 공통 값 세팅
agre.setOrderId(orderId);
agre.setUserType("MAIN");
agre.setCreatedAt(now);
// 기본 동의
agre.setAgreeItems(baseAgreeList);
baseAgre.setExtraYn("N");
mapper.insert(agre);
// 추가 동의
if (!extraAgreeList.isEmpty()) {
agre.setAgreeItems(extraAgreeList);
baseAgre.setExtraYn("Y");
mapper.insert(agre);
}
겉보기에는 문제가 없어 보이고, 실제로도 정상적으로 insert는 수행된다.
하지만 이 구조에는 몇 가지 근본적인 문제가 있다.
같은 객체를 수정해서 다시 insert 하면 코드를 읽는 입장에서는 자연스럽게 이런 의문이 든다.
이 객체는 이미 DB에 들어간 상태 아닌가?
PK나 식별 값은 어디서 관리되는가?
update와 무엇이 다른가?
의도가 코드에 드러나지 않아 이해 비용이 커진다.
현재는 필드가 단순해서 괜찮아 보일 수 있다.
하지만 시간이 지나면서 다음과 같은 변화가 생긴다.
컬럼 추가
insert 조건 분기 증가
기본값 세팅 로직 변경
이 순간부터 이전 insert의 값이 다음 insert에 섞여 들어갈 위험이 생긴다.
동의, 로그, 이력 테이블은 “언제, 무엇이, 왜 저장됐는지”가 중요하다.
객체 하나를 계속 수정해서 여러 row를 만드는 구조는
장애 분석과 디버깅 시 추적 난이도를 크게 높인다.
원칙은 단순하다.
insert = 객체 1개 = row 1개
공통 세팅은 메서드로 분리하고, 각 insert마다 새 객체를 생성한다.
private Agreement baseAgreement(String orderId, LocalDateTime now) {
Agreement agre = new Agreement();
agre.setOrderId(orderId);
agre.setUserType("MAIN");
agre.setCreatedAt(now);
return agre;
}
// 기본 동의
Agreement baseAgre = baseAgreement(orderId, now);
baseAgre.setAgreeItems(baseAgreeList);
baseAgre.setExtraYn("N");
mapper.insert(baseAgre);
// 추가 동의
if (!extraAgreeList.isEmpty()) {
Agreement extraAgre = baseAgreement(orderId, now);
extraAgre.setAgreeItems(extraAgreeList);
extraAgre.setExtraYn("Y");
mapper.insert(extraAgre);
}
insert 로직에서 객체 재사용은 당장은 코드가 짧아 보일 수 있지만, 시간이 지날수록 유지보수 비용이 커진다. 특히 동의·로그·이력 데이터라면 객체를 아끼기보다 명확한 구조를 선택하는 게 맞다.
insert는 항상 “이 객체는 하나의 row만 책임진다” 라는
원칙을 지키는 것이 가장 안전하다.