기록 111

[MapStruct] 내부 구현 방식 - 설계 문제 해결

문제 상황BaseEntity에서 @Setter를 제거했더니 MapStruct Mapper에서 컴파일 오류가 발생했다.error: Property "id" has no write accessor in User for target name "user.id". ReadStatus toEntity(ReadStatusCreateRequest request);error: Property "id" has no write accessor in Channel for target name "channel.id". ReadStatus toEntity(ReadStatusCreateRequest request);처음엔 단순히 Setter가 없어서 생긴 오류라고 생각했다.ignore = true를 붙이거나 Setter..

JPA Dirty Checking과 명시적 save는 무슨 차이일까?

1. Dirty Checking이란영속성 컨텍스트는 엔티티를 처음 조회하거나 persist할 때 해당 시점의 스냅샷을 내부에 보관합니다. 트랜잭션 커밋 시점에 flush가 호출되면서 현재 엔티티 상태와 스냅샷을 필드 단위로 비교해, 변경이 있으면 자동으로 UPDATE SQL을 생성합니다. 이것이 Dirty Checking입니다.트랜잭션 커밋 ↓entity manager의 flush 자동 호출 ↓dirty checking (현재 상태 vs 스냅샷 비교) ↓변경 감지 → UPDATE SQL 생성 → DB 전송 ↓JDBC commit (영구 반영)따라서 같은 트랜잭션 내에서 엔티티를 조회하고 수정하면, save() 호출 없이도 트랜잭션 커밋 시 UPDATE가 자동으로 발생합니다.@Tran..

Java & Spring/JPA 2026.04.09

Spring Data JPA는 내부적으로 어떻게 동작할까?

1. JPA vs Spring Data JPA둘을 혼용해서 쓰는 경우가 많지만 역할이 다릅니다.**JPA (Java Persistence API)**는 자바 ORM 표준 명세입니다. 인터페이스만 정의하고, 실제 구현체는 Hibernate가 담당합니다.Spring Data JPA는 JPA 위에 얹힌 추상화 레이어입니다. JpaRepository를 상속하는 것만으로 findById(), save(), delete() 같은 기본 CRUD를 자동으로 제공합니다.Spring Data JPA ↓ JPA (인터페이스) ↓ Hibernate (구현체) ↓ JDBC ↓ DB즉, 우리가 userRepository.save(user)를 호출하면 내부적으로 Hibernat..

Java & Spring/JPA 2026.04.09

Git 협업 플로우 — PR 올리기 전 필수 순서 정리

협업 시 브랜치 동기화, merge, rebase 어떤 순서로 해야할지 헷갈려 정리해보았다!1. 상황 설정공용 브랜치는 develop나는 feature/login 브랜치에서 작업 중작업하는 동안 팀원이 feature/payment를 develop에 먼저 머지한 상태develop: A --- B --- C --- D (팀원 커밋) \feature/login: X --- Y --- Z (내 커밋)이 상태에서 PR을 올리면 develop과 feature/login 사이에 격차가 생겨 컨플릿이 발생할 수 있습니다.2. 전체 흐름 한눈에 보기① local develop pull ↓② feature rebase develop ↓③ f..

Git & GitHub 2026.04.09

Merge Conflict는 발생하는 이유가 뭘까?

1. Merge Conflict란?Git은 두 브랜치를 병합할 때 변경 사항을 자동으로 합친다.그러나 같은 파일의 같은 라인을 두 브랜치가 서로 다르게 수정했다면, Git은 어느 쪽이 맞는지 판단할 수 없다. 이 상태가 바로 Merge Conflict이다.참고 — Git이 자동으로 합칠 수 있는 경우(서로 다른 파일 수정, 같은 파일의 다른 라인 수정)는 컨플릿 없이 머지됩니다. 컨플릿은 정말로 충돌이 일어났을 때만 발생한다.2. 발생 원인Merge Conflict의 근본 원인은 두 브랜치가 서로의 변경 사항을 모르는 채로 같은 라인을 수정했을 때다. 반대로, 한 브랜치가 다른 브랜치의 커밋 이력을 포함하고 있다면 Git은 충돌 없이 머지할 수 있다.시나리오 1 — 동일 파일, 동일 라인 수정가장 흔한 ..

Git & GitHub 2026.04.09

Prefect - 오케스트레이션

오케스트레이션이란오케스트레이션(Orchestration)은 여러 작업을 순서대로, 조건에 맞게, 안정적으로 실행하는 것을 말한다.오케스트라에서 지휘자가 각 파트(바이올린, 첼로, 플루트)를 박자에 맞춰 조율하는 것과 같다. 각 연주자(작업)는 자기 역할만 하고, 지휘자(오케스트레이터)가 전체 흐름을 책임진다.데이터 파이프라인으로 예를 들면, 아래 같은 상황이 생긴다.1. 외부 API에서 데이터 수집2. 수집한 데이터 정규화3. 중복 제거 후 DB 저장4. 저장 완료되면 슬랙 알림이걸 그냥 순서대로 실행하는 Python 스크립트를 짜면 되지 않냐고 할 수 있다. 근데 실제로는 문제가 생긴다.2번에서 실패하면 1번부터 다시 해야 하나?어느 단계에서 실패한 건지 로그 뒤져야 알 수 있음매일 자동 실행하려면 c..

Python 2026.04.07

Alembic - 스키마 버전 관리

Alembic이 필요한 이유DB 스키마를 바꿀 때 흔히 하는 실수가 있다. CREATE TABLE SQL을 직접 실행하거나, 팀원들이 각자 DDL을 돌리는 방식이다.문제는 재현성이다. 어떤 DDL이 어떤 순서로 실행됐는지 추적이 안 된다. 새 팀원이 환경을 셋업할 때, 스테이징에서 프로덕션으로 배포할 때 매번 수동으로 맞춰야 한다.Alembic은 마이그레이션을 파일로 관리한다. 각 파일은 upgrade() (스키마 적용)와 downgrade() (롤백)를 담고, 파일 간 연결은 revision ID로 이어진다. alembic upgrade head 한 번으로 현재 DB를 최신 상태로 만들 수 있다.초기 셋업# 프로젝트 루트에서alembic init alembic이 명령어 하나로 alembic/ 디렉토리와..

Python 2026.04.07

SQLAlchemy - Python ORM

ORM이란ORM(Object-Relational Mapping)은 DB 테이블을 Python 클래스로, 행(row)을 객체로 다루게 해주는 기술이다.ORM 없이 PostgreSQL을 쓰면 이렇게 된다.cursor.execute(""" INSERT INTO users (email, username) VALUES (%s, %s)""", ("hello@example.com", "goran"))SQLAlchemy ORM을 쓰면 이렇게 된다.user = User(email="hello@example.com", username="goran")session.add(user)session.commit()SQL을 직접 쓰지 않아도 되고, Python 객체처럼 다룰 수 있어서 코드가 일관성 있어진다. 타입 힌트도 붙..

Python 2026.04.07

Git — 커밋 컨벤션 · Branch 전략

Git — 커밋 컨벤션 · Branch 전략혼자 쓸 때와 팀으로 쓸 때의 Git은 다르다. 약속이 생산성을 만든다.1. 커밋 메시지 컨벤션 (Conventional Commits)왜 필요한가커밋 메시지는 코드만큼 중요한 문서다. 메시지가 일관성 없으면 히스토리가 노이즈가 되고, 나중에 "이 변경이 왜 들어갔지?"를 추적하기 어려워진다. Conventional Commits는 커밋 메시지의 구조를 표준화하는 스펙이다.기본 형식(): [body][footer]type — 변경의 종류 (필수)scope — 변경된 범위, 모듈명 등 (선택)subject — 변경 내용 요약, 50자 이내, 마침표 없음 (필수)body — 변경 이유, 상세 설명 (선택)footer — Breaking Change, 이슈 참조 등 ..

Git & GitHub 2026.04.06

Git Merge vs Rebase - 언제 쓰고, 무슨 차이일까?

Git Merge vs Rebase — 같은 목표, 다른 철학두 명령어의 차이를 이해하면 팀의 Git 히스토리가 달라집니다.1. 둘 다 "브랜치를 합친다"merge와 rebase는 모두 한 브랜치의 변경 사항을 다른 브랜치에 통합하기 위한 명령어다. 목적은 동일하지만, 히스토리를 만들어가는 방식이 근본적으로 다르다.Merge — 두 브랜치가 합쳐졌다는 기록 자체를 남긴다.Rebase — 커밋들을 다른 브랜치의 끝에 마치 처음부터 거기서 작업한 것처럼 재작성한다.2. 히스토리 구조 비교git mergeA --- B --- C ----------- M ← main (M = merge commit) \ / F1 --- F2 ← fea..

Git & GitHub 2026.04.06