Biz Assist에서 같은 공지를 여러 번 알리지 않게 만들면서
UNIQUE 제약조건을 사용했다.
CONSTRAINT uk_notification_delivery_dedup UNIQUE (
channel,
notification_type,
source_code,
external_id,
content_fingerprint
)
UNIQUE는
특정 컬럼 값의 조합이 중복되지 않게 막는 제약조건이다.
예를 들어 위 코드는
채널
알림 유형
출처
공지 ID
내용 fingerprint
이 다섯 값의 조합이 똑같은 데이터는
두 번 저장할 수 없게 만든다.
코드에서 먼저
이미 저장돼 있나?
를 조회한 다음 저장할 수도 있다.
근데 동시에 두 작업이 실행되면
A → 없음 확인
B → 없음 확인
A → 저장
B → 저장
처럼 둘 다 저장될 수 있다.
그래서 최종 중복 방지는
DB가 직접 맡도록 했다.
알림 후보를 저장할 때
일단 INSERT를 시도한다.
try {
jdbcTemplate.update(...);
} catch (DuplicateKeyException ignored) {
return Optional.empty();
}
이미 같은 알림 이력이 있으면
DB의 UNIQUE 제약조건 때문에 저장이 실패한다.
그때 발생한 DuplicateKeyException을 잡아서
이미 만들어진 알림
→ 새 후보를 만들지 않음
으로 처리했다.
처음에는 external_id 하나만 중복 방지하면 되는 줄 알기 쉽다.
근데 같은 공지라도
내용이 수정될 수 있다.
그래서 Biz Assist에서는
external_id
+
content_fingerprint
를 같이 사용했다.
같은 공지 ID라도 내용이 바뀌어
fingerprint가 달라지면 새로운 알림으로 볼 수 있다.
반대로 ID와 내용이 모두 같으면
중복 알림으로 막힌다.
둘 다 중복을 막지만 역할이 조금 다르다.
PRIMARY KEY
→ 행 자체를 식별하는 대표 키
UNIQUE
→ 특정 값이나 값의 조합이 중복되지 않게 제한
notification_delivery에서는
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
가 행을 구분하고
알림 중복 여부는 별도의 UNIQUE 제약조건이 담당한다.
UNIQUE
→ 중복되면 안 되는 값에 걸어두는 DB 제약조건
복합 UNIQUE
→ 여러 컬럼의 조합을 하나의 중복 기준으로 사용
DuplicateKeyException
→ UNIQUE 같은 제약조건 위반을 Java에서 처리할 때 사용 가능
Biz Assist에서는
같은 공지의 같은 내용을 두 번 알림 후보로 만들지 않기 위해 UNIQUE를 사용했다.
코드에서 중복을 검사하는 것도 필요하지만
마지막 중복 방지는 DB 제약조건에 맡길 수 있다는 걸 다시 봤다.