“Boot 4와 Java 25로 새 프로젝트를 만든다면, DB 접근은 뭘로 할까?”
지난 두 글에서는 ‘기준선을 올리는’ 이야기를 했다. Spring Boot 4는 Framework 7, Jakarta EE 11, Jackson 3, JSpecify를 가져왔고, Java 25는 record, sealed, pattern matching, virtual threads로 코드 톤을 바꾼다.
그러면 다음 질문은 자연스럽다.
“이 기준선 위에서 새 프로젝트를 시작한다면 데이터 접근 기술은 뭘 고를까?”
예전에는 답이 비교적 단순했다. ‘업무 시스템이면 JPA, 동적 쿼리는 QueryDSL, SI나 레거시 SQL이면 MyBatis’. 그런데 2026년에는 선택지가 조금 더 넓어졌다. 복잡 SQL을 타입 안전하게 다루는 jOOQ, JPA보다 단순한 Spring Data JDBC, Kotlin 쪽의 Exposed 1.0, SQL 파일 기반 codegen 철학을 보여주는 sqlc까지.
이 글은 ‘JPA가 답이냐, ORM은 실수냐’ 같은 논쟁을 하려는 글이 아니다. ‘Spring Boot 4 + Java 25 시대에 새 프로젝트를 만든다면 어떤 SQL 접근 기술을 어떤 자리에 놓을지’ 정리하는 글이다. 시리즈 ‘Legacy Escape’의 3편이고, 1·2편이 ‘Boot 4 / Java 25로 기준선을 올리는’ 이야기였다면 이번은 ‘그 위에서 새 프로젝트의 SQL 접근 스택을 고르는’ 이야기다.

결론 먼저: 최신 Spring 프로젝트라면 이렇게 본다
‘한 줄 요약: 신규 Java/Spring 프로젝트라면 JPA와 jOOQ를 먼저 본다. MyBatis는 새 프로젝트의 기본값이라기보다 레거시 SQL 자산과 조직 제약이 있을 때 선택하는 현실적인 카드다.’
| 프로젝트 성격 | 추천 기본값 |
|---|---|
| 일반적인 업무 시스템, CRUD, 도메인 객체 중심 | Spring Data JPA |
| JPA 기반이지만 검색 조건이 복잡함 | Spring Data JPA + QueryDSL |
| 복잡 SQL, 통계, 리포트, 대시보드 중심 | jOOQ |
| JPA는 무겁지만 Spring 생태계 안에서 단순하게 가고 싶음 | Spring Data JDBC / JdbcClient |
| 기존 MyBatis SQL 자산이 많거나 SI 표준이 MyBatis | MyBatis |
| 고객사·DBA가 SQL 파일을 직접 관리함 | MyBatis |
| Kotlin 신규 프로젝트 | Exposed 1.0 또는 jOOQ |
| Go에서 SQL 파일 기반 codegen | sqlc (Java/Spring 주류 후보는 아님) |
본문에서 각 자리를 차례로 본다. 마지막에 ‘내 프로젝트는 어디?’를 정리할 6질문 체크리스트를 둔다.
잠깐 — ‘ORM은 실수였다’ 논쟁은 뭔가요?
트위터·HN을 돌아다니다 보면 “ORM은 실수였다”, “직접 SQL 써라” 같은 강한 주장을 본다. 배경은 단순하다. JPA/Hibernate 같은 풀-기능 ORM은 객체 모델로 DB를 추상화해주지만, 그 대신 ‘lazy loading 함정, N+1, 자동 flush, 캐시 정합성, JPQL 한계’ 같은 비용을 떠안는다. 복잡한 쿼리에선 결국 SQL을 쓰는데, 그러면서도 ORM의 무게는 그대로다.
반대 진영도 있다. “그래도 단순 CRUD에서 ORM이 주는 생산성은 크다”, “JPA를 잘 쓰면 대부분 문제는 피할 수 있다”는 입장.
이 글은 어느 쪽이 옳다고 결론 짓지 않는다. 다만 ‘2026년의 자바·Kotlin 생태계는 둘 사이에 놓인 도구가 풍부해졌다’는 사실을 본다. JPA를 버려야 한다는 얘기가 아니라, ‘쓸 수 있는 카드가 많아졌다’는 얘기다.
먼저 선택지를 세 갈래로 나누자
‘한 줄 요약: 객체 중심, SQL 중심, Kotlin 중심. 도구 이름을 외우기 전에 결의 차이부터 잡는다.’
데이터 접근 도구는 종종 ‘JPA vs MyBatis vs jOOQ’ 같은 한 줄로 비교되지만, 사실 결이 다 다르다. 세 갈래로 묶으면 이해가 쉽다.
- ‘객체 중심’: 도메인 객체와 테이블을 매핑하고, 트랜잭션 안에서 객체 그래프를 다룬다. — Spring Data JPA, (Spring Data JDBC도 객체 매핑 쪽 절충안에 가깝다.)
- ‘SQL 중심’: SQL을 자산으로 두고, 매핑·타입 검사만 도구가 돕는다. — jOOQ, MyBatis, JdbcClient, sqlc.
- ‘Kotlin 중심’: Kotlin 친화 DSL과 코루틴/R2DBC 흐름을 함께 본다. — Exposed.
이 세 결을 의식하면, 도구 비교가 ‘경쟁’이 아니라 ‘내 프로젝트의 결과 짝짓기’가 된다.
기본값 1 — Spring Data JPA는 여전히 강하다
‘한 줄 요약: 객체 모델로 풀 수 있는 도메인이라면 가장 생산적인 디폴트. 단, “JPA만 쓰면 다 된다”는 가정이 깨지는 자리도 분명히 있다.’
잘 맞는 자리
- 도메인 객체와 테이블 구조가 자연스럽게 매핑되는 시스템 (전형적인 사내 업무 시스템, 관리 도구, CMS 등)
- CRUD가 비즈니스 로직의 큰 비중을 차지하는 서비스
- 트랜잭션 경계 안에서 객체 그래프를 다루는 패턴이 일반적인 도메인
어색해지는 자리
- 보고서/통계처럼 ‘GROUP BY, 윈도우 함수, CTE, UNION’이 본질인 쿼리
- 벤더 특화 기능(Postgres
JSONB, MySQLJSON_TABLE등)을 적극 쓰는 환경 - 한 화면에 수십 개 컬럼을 쥐어짜야 하는 ‘대시보드 백엔드’
자세한 N+1·페치 조인·트랜잭션 패턴은 Spring Garden 4편(N+1과 Fetch Join)과 Spring Garden 6편(트랜잭션과 동시성) 참고.
기본값 2 — 복잡 SQL이면 jOOQ를 먼저 본다
‘한 줄 요약: “코드가 곧 SQL”인 타입 안전 DSL. 통계·리포트·벤더 특화 기능이 본질인 프로젝트의 새 기본값 후보.’
jOOQ는 ‘데이터베이스 메타데이터에서 자바 코드를 생성’하고, 그 코드로 SQL을 표현한다. 결과적으로 ‘SQL 같은 모양의 자바 코드’가 된다.
// jOOQ 예시
Result<Record3<Long, String, LocalDateTime>> result = ctx
.select(USERS.ID, USERS.EMAIL, USERS.CREATED_AT)
.from(USERS)
.where(USERS.STATUS.eq("ACTIVE"))
.and(USERS.EMAIL.likeIgnoreCase("%" + keyword + "%"))
.orderBy(USERS.CREATED_AT.desc())
.fetch();
강점
- ‘코드 곧 SQL’이라 학습 마찰이 적다. SQL을 아는 사람은 바로 익는다.
- ‘컴파일 타임 타입 검사’가 매우 강하다. 컬럼 삭제·타입 변경 같은 스키마 변화가 컴파일 에러로 떠오른다.
- ‘DB 벤더별 SQL 방언’을 일등 시민으로 다룬다. Postgres
JSONB, 윈도우 함수, CTE, MERGE 등이 자연스럽다. - 동적 쿼리·복잡 조건 조합이 강력하다.
약점
- ‘스키마 codegen’이 빌드 파이프라인에 추가된다. 마이그레이션과 codegen 시점을 잘 묶어둬야 한다.
- 라이선스 — Open Source 라이선스는 OSS 라인 DB(Postgres, MySQL, MariaDB, SQLite, H2 등)만 무료. ‘Oracle DB·SQL Server·DB2 등 상용 DB는 유료 라이선스가 필요한 모듈’을 쓴다. 도입 전 확인 필수.
- ‘도메인 객체 ↔ 테이블 매핑’은 jOOQ가 직접 풀어주지 않는다. ORM 사고가 깊은 팀은 패러다임 전환이 필요.
2026 시점
복잡 분석 쿼리·통계·대시보드 백엔드를 자바/Kotlin으로 짜는 팀에서 채택이 꾸준히 늘고 있다. JPA와 한 프로젝트에 공존하는 패턴(영속성=JPA, 조회=jOOQ)도 흔하다. 신규 프로젝트의 ‘SQL 중심’ 자리에서는 MyBatis보다 jOOQ를 먼저 검토할 만한 시점에 와 있다.
MyBatis — 새 기본값인가, 레거시 친화 선택인가
‘한 줄 요약: 죽은 기술은 아니다. 다만 신규 프로젝트의 기본값이라기보다, 기존 SQL 자산과 SI 현실을 다루는 카드에 가깝다.’
MyBatis는 ‘객체 ↔ SQL 매핑’ 도구다. SQL은 XML이나 어노테이션에 그대로 쓰고, 결과를 객체로 받는다. 자바 진영의 풀-기능 ORM이 아닌 ‘경량 SQL 매퍼’ 진영의 대표주자.
<select id="findActiveUsersByKeyword" resultType="User">
SELECT id, email, name, created_at
FROM users
WHERE status = 'ACTIVE'
<if test="keyword != null">AND email LIKE CONCAT('%', #{keyword}, '%')</if>
<if test="since != null">AND created_at >= #{since}</if>
ORDER BY created_at DESC
</select>
2026 시점에도 유효한 강점
- ‘SQL을 100% 그대로 쓸 수 있다.’ 벤더 특화 기능, 옵티마이저 힌트까지 자유.
- 학습 곡선이 얕다. SQL을 아는 사람은 바로 시작.
- 한국 SI 현장에서 광범위하게 쓰여 인력 풀이 두텁다.
- MyBatis Spring Boot Starter가 ‘Spring Boot 4.0 + Java 17+ + MyBatis-Spring 4.0’ 라인을 지원한다고 정리돼 있고, 4.0.1 같은 패치 릴리즈도 나왔다. ‘낡아서 못 쓰는 기술이 아니다.’
약점
- ‘컴파일 타임 타입 검사가 약하다.’ 컬럼 오타, 결과 타입 불일치는 런타임에 발견.
- XML 분기 조립이 길어지면 가독성이 무너진다.
2026 시점의 포지셔닝
MyBatis는 최신 프로젝트의 ‘기술적으로 가장 진보한 기본값’은 아니다. 하지만 SI 현장에서 ‘납기, 인력, 기존 SQL 자산, 고객사 표준, 상용 DB 라이선스’까지 고려하면 아직도 안전한 선택지가 될 수 있다.
정리하면, 신규 프로젝트가 ‘SQL 중심’이라면 ‘jOOQ가 더 강한 후보’가 됐다. 다만 다음 중 하나라도 해당하면 MyBatis는 여전히 현실적이다.
- 기존 SQL/Mapper 자산이 많고 그대로 가져가야 한다
- 고객사·DBA가 SQL 파일을 직접 관리한다
- SI 인력 풀과 사내 표준이 MyBatis다
- 상용 DB(Oracle/SQL Server 등)에서 jOOQ 라이선스 비용 부담이 크다
- codegen 파이프라인 운영 부담을 추가로 지기 어렵다
JPA와 비교 관점은 MyBatis vs JPA: 어떻게 같이 쓰나 참고.
QueryDSL은 '기본값'이 아니라 'JPA 보완재'
‘한 줄 요약: 독립 데이터 접근 전략이 아니라, JPA를 골랐을 때 동적 쿼리를 보완하는 카드.’
QueryDSL은 별개 ORM이 아니라 ‘JPA 위에서 타입 안전한 쿼리를 짜는 DSL’이다. 컴파일 시점에 Q클래스를 생성해 컬럼·조건을 코드로 표현한다.
이 글에서 중요한 점은 이거다. ”JPA냐 jOOQ냐 MyBatis냐’를 고르는 층과, ‘JPA를 골랐을 때 QueryDSL을 붙일까’를 고르는 층은 다르다.” 그래서 위 결론 표에서 QueryDSL은 ‘JPA의 보완재’ 자리에만 등장한다.
자세한 사용 패턴은 Spring Garden 3편(QueryDSL과 동적 쿼리) 참고.
Spring Data JDBC / JdbcClient도 빼먹지 말자
‘한 줄 요약: JPA보다 단순한 Spring 친화 SQL 접근. “JPA는 무거운데 raw JDBC는 너무 낮다” 사이를 메운다.’
Spring 진영에는 JPA만 있는 게 아니다. ‘Spring Data JDBC’와 ‘JdbcClient'(Spring Framework 6.1+)도 같은 생태계 안에서 데이터 접근을 푸는 옵션이다.
- ‘Spring Data JDBC’: aggregate 추상화, 어노테이션 기반 entity 매핑, immutable entity, query derivation,
@Query커스텀 쿼리. JPA보다 가볍고 동작 모델이 단순하다(영속성 컨텍스트·자동 flush 없음). - ‘JdbcClient’: Spring Framework가 제공하는 ‘fluent JDBC API’. raw JdbcTemplate보다 쓰기 좋고, named parameters·결과 매핑이 깔끔하다.
잘 맞는 자리
- ‘단순 repository로 충분한’ 마이크로서비스
- 영속성 컨텍스트의 마법(자동 flush, 1차 캐시)을 원하지 않는 팀
- ‘예측 가능성’이 우선인 환경 — SQL이 뭐가 나가는지가 명시적으로 보여야 하는 곳
한계
- 복잡 도메인 그래프 매핑은 JPA만큼 풀어주지 않는다.
- jOOQ 같은 SQL DSL의 ‘코드가 곧 SQL’ 표현력은 없다.
신규 Spring 프로젝트에서 ‘JPA만큼 무거운 게 부담’이고 ‘jOOQ만큼 SQL 중심도 아닌’ 자리가 의외로 많다. 그 자리에 Spring Data JDBC / JdbcClient가 들어간다.
Kotlin이면 Exposed를 검토한다
‘한 줄 요약: Kotlin/Spring Boot 4 신규 프로젝트라면 Exposed 1.0이 검토 카드. Java 팀이라면 jOOQ나 Spring Data 계열이 더 자연스럽다.’
Exposed는 JetBrains의 Kotlin SQL 라이브러리다. 2026년 1월 첫 메이저 릴리즈인 1.0이 나오면서 stable API, R2DBC 지원, 성능 개선을 강조했다. Spring Boot 4 통합용 ‘exposed-spring-boot4-starter’도 안내된다(autoconfiguration + transaction 통합).
val users = transaction {
Users
.select { (Users.status eq "ACTIVE") and (Users.email like "%$keyword%") }
.orderBy(Users.createdAt to SortOrder.DESC)
.map { it[Users.id] to it[Users.email] }
}
잘 맞는 자리
- Kotlin/Spring Boot 4 백엔드, Ktor
- 코루틴·R2DBC 같은 비동기 흐름이 본질인 서비스
한계
- ‘Kotlin 전용’. Java 일반 백엔드에는 부적합.
- 큰 SI 환경에서는 인력 풀이 좁다.
Java/Spring 신규 프로젝트라면 Exposed는 ‘주류 후보’라기보다 ‘Kotlin을 선택했을 때 올라오는 카드’다. Kotlin + Boot 4 조합에서는 Exposed 1.x와 starter 덕분에 검토 가치가 커졌지만, Java 팀이라면 jOOQ나 Spring Data 계열이 더 자연스럽다.
sqlc는 왜 언급하나
‘한 줄 요약: SQL 우선 + 코드 자동 생성이라는 철학을 가장 선명하게 보여주는 도구. 다만 Java/Spring 주류 후보는 아니다.’
sqlc는 Go 진영에서 시작한 도구로, ‘SQL 파일을 먼저 쓰고 타입 안전한 코드를 생성’한다.
-- queries.sql -- name: FindActiveUsersByKeyword :many SELECT id, email, name, created_at FROM users WHERE status = 'ACTIVE' AND email ILIKE '%' || $1 || '%' ORDER BY created_at DESC;
빌드 시점에 SQL을 분석해 함수와 결과 타입을 생성한다.
다만 ‘Java/Spring 신규 프로젝트의 실전 후보로는 아직 중심에 두기 어렵다.’ 공식 문서 기준 Go는 stable, Kotlin/Python/TypeScript는 beta, Java는 community plugin beta로 분류된다. Java에서는 비슷한 문제(SQL 우선 + 타입 안전 코드)를 jOOQ codegen이 더 자연스럽게 푼다.
따라서 이 글에서 sqlc는 ‘직접 도입 후보’라기보다 ‘SQL-first codegen이라는 흐름을 설명하는 참고 카드’다. Go 진영을 보거나, ‘쿼리 카탈로그’ 같은 디자인을 자바에서 흉내 낼 때 영감을 얻기 좋다.
어떻게 골라야 하나 — 6질문 체크리스트
‘한 줄 요약: 도구를 먼저 고르지 말고, 내 프로젝트의 6가지 질문에 답한 뒤에 고른다.’
| 질문 | 답에 따라 |
|---|---|
| 1. 도메인이 객체 모델 중심인가, SQL 중심인가? | 객체 → JPA, SQL → jOOQ/MyBatis/JdbcClient |
| 2. 단순 CRUD가 큰 비중인가, 복잡 조회·통계가 큰가? | CRUD → JPA, 통계 → jOOQ |
| 3. 동적 조건이 많은가? | 많음 → QueryDSL(JPA 보완)/jOOQ, 적음 → MyBatis/JdbcClient |
| 4. 벤더 특화 SQL을 쓰는가? | 많이 씀 → jOOQ/MyBatis |
| 5. JPA 영속성 컨텍스트의 자동 동작이 부담스러운가? | 그렇다 → Spring Data JDBC / JdbcClient |
| 6. Java인가 Kotlin인가? | Kotlin이면 Exposed 추가 검토 |
이 6가지가 분명해지면 도구는 거의 자동으로 좁혀진다. ‘JPA + QueryDSL 디폴트’, ‘복잡 분석은 jOOQ’, ‘레거시 SQL 자산은 MyBatis’, ‘가벼운 Spring SQL은 Spring Data JDBC’, ‘Kotlin 신규는 Exposed’ — 이런 식이다.
한 프로젝트에 여러 도구가 같이 사는 패턴
‘한 줄 요약: 한 도구로 모든 자리를 풀려고 하지 말고, “레이어별로 다른 도구”가 더 현실적인 답일 때가 많다.’
실무에서 흔히 보는 모양은 이렇다.
- ‘영속성 레이어 = JPA’: 도메인 객체 매핑, 트랜잭션, 캐시
- ‘복잡 조회 = jOOQ’: 검색/필터, 동적 조건, 통계, CTE
- ‘단순 SQL 보조 = JdbcClient’: 트리거 같은 소형 쿼리
- ‘레거시 SQL 자산 = MyBatis’: 기존 자산을 그대로 가져온 모듈
같은 프로젝트에 두세 도구가 공존하는 건 어색한 게 아니다. 오히려 ‘한 도구로 다 풀려고 무리하다 보면 어딘가는 망가진다’.
다만 두 가지 조건이 있다.
- ‘레이어 경계가 명확’해야 한다. 같은 데이터를 두 도구로 동시에 다루지 않는다.
- ‘팀 합의’가 있어야 한다. “이 화면은 이 도구로”가 사람마다 다르면 결국 한 도구로 통일하는 것보다 비용이 커진다.
마치며: 도구가 아니라 프로젝트의 결을 고른다
Spring Boot 4와 Java 25는 단순히 버전 숫자를 올리는 변화가 아니다. 그 위에서 새 프로젝트를 시작한다면 ‘데이터 접근 기술도 예전 관성으로만 고르면 안 된다’.
요약하면:
- ‘JPA’는 여전히 강력한 기본값이고, ‘QueryDSL’은 JPA의 좋은 보완재다.
- SQL이 프로젝트의 중심이라면 이제 ‘MyBatis보다 jOOQ를 먼저 검토할 만하다’.
- ‘MyBatis’는 죽은 기술이 아니라, 레거시 SQL 자산과 SI 현실을 다루는 카드다.
- ‘Spring Data JDBC / JdbcClient’는 ‘JPA는 무겁고 jOOQ는 부담스러운’ 자리에 들어가는 절충안.
- Kotlin이라면 ‘Exposed 1.0’이 새 후보로 올라왔다.
- ‘sqlc’는 직접 후보보다 ‘SQL 우선 codegen’ 철학의 참고 카드.
- 한 프로젝트에 여러 도구가 공존하는 게 자연스럽다. 레이어 경계와 팀 합의만 있으면.
결국 ‘도구를 고르는 게 아니라 프로젝트의 결을 고르는 일’이다. 이전 두 글이 ‘Boot 4와 Java 25라는 기준선을 어디까지 올릴까’였다면, 이 글은 그 위에서 ‘JPA 한 줄 정답을 의심해보는 시점’을 짚은 것이다.
다음 Legacy Escape 글로는 ‘Spring Boot 2 → 3 (Jakarta 전환)’이나 ‘Vue 2 → Vue 3, Vuex → Pinia’ 같은 마이그레이션 주제를 이어갈 예정이다. 시리즈는 계속 ‘운영 중인 프로젝트의 기준선 이동’을 따라간다.
📦 추가 메모: 도입 결정에 필요한 디테일
jOOQ 라이선스 한 번 더
- ‘OSS 라이선스(Apache 2.0)’: Postgres, MySQL, MariaDB, SQLite, H2, HSQLDB, Derby, CockroachDB, YugabyteDB, ClickHouse 등 주요 OSS DB.
- ‘상용 라이선스 필요’: Oracle DB, SQL Server, DB2, Snowflake, Redshift, Sybase, Informix 등.
- ‘Spring Boot Starter’는 OSS 라인에서 제공. 상용 DB로 이동할 때 라이선스 모델과 비용을 사전에 검증.
- ‘권고’: 도입 전에 ‘jOOQ 공식 라이선스 페이지’와 사내 법무 검토를 묶어 한 번에 처리.
codegen 파이프라인 설계 팁
- ‘jOOQ’: Gradle/Maven 플러그인이 표준. ‘Flyway/Liquibase 마이그레이션 → DB 스키마 적용 → codegen’ 순서를 한 빌드 단계에 묶는다. 로컬·CI 동일하게.
- ‘sqlc 계열’:
schema.sql(또는 마이그레이션 산출물) +queries.sql을 입력으로 두고,sqlc generate로 코드 생성. 마이그레이션 변경이 코드 생성을 깨면 PR에서 즉시 보인다. - ‘QueryDSL’: APT 기반. 멀티 모듈에서
Q클래스가 어느 모듈에 생성되는지 한 번 정리해두지 않으면 import 지옥이 시작된다.
트랜잭션·세션 관리
- ‘JPA’: 영속성 컨텍스트 + 1차 캐시 + auto flush. 트랜잭션 경계와 강하게 묶임.
- ‘Spring Data JDBC / JdbcClient’: 영속성 컨텍스트가 없다. ‘Repository 호출 = SQL 실행’에 가까워 예측이 쉽다.
- ‘jOOQ / MyBatis’: ‘DB 세션’ 수준에서 동작. 1차 캐시 같은 자동 동작이 없어 ‘예측 가능성’이 높지만, 일관성은 개발자가 책임.
- ‘Exposed’:
transaction {}블록으로 명시적 경계. R2DBC 흐름에서는 코루틴 컨텍스트와 연동.
마이그레이션 도구와의 짝
- ‘Flyway/Liquibase’ 같은 스키마 마이그레이션 도구는 위 도구들 모두와 호환. 도구 선택과 무관하게 ‘스키마 변경 = 마이그레이션 파일’로 관리.
- jOOQ는 ‘마이그레이션 산출물 = 코드 생성 입력’으로 한 번 더 묶이는 짝이라 일관성이 강해진다.
관측성과 로그
- ‘JPA’: Hibernate 통계,
spring.jpa.show-sql(개발용), p6spy/datasource-proxy로 운영 트레이스. SQL이 자동 생성되므로 ‘실제 나가는 쿼리’를 항상 보는 습관 필수. - ‘jOOQ / MyBatis / JdbcClient’: 코드가 SQL과 가까워서 추적이 쉽다. 다만 동적 분기가 많은 자리에선 ‘EXPLAIN’을 자주 봐야 함.
- ‘OpenTelemetry’: 위 도구들 모두 JDBC 계층에서 통합 가능. ‘쿼리 단위’ 트레이스를 표준화.
MyBatis를 새 프로젝트에 골라야 한다면
- ‘버전 라인업’: MyBatis Spring Boot Starter 4.0.x + MyBatis 3.5.x + MyBatis-Spring 4.0.x로 묶는다.
- ‘XML vs 어노테이션’: 동적 분기가 적은 단순 매퍼는 어노테이션, 동적 SQL이 많은 화면은 XML이 일반적.
- ‘@MapperScan 위치’: 멀티 모듈에서는 한 모듈에 매퍼를 모아두는 편이 유지보수가 쉽다.
- ‘코드 리뷰 체크리스트’: 동적 SQL
<if>누락,resultMap컬럼 매핑, 결과 타입 일치, NULL 처리.
한 줄 정리
”Boot 4 + Java 25 위에서 새 프로젝트를 시작한다면, JPA 한 줄 정답을 의심하는 시점에 와 있다. 도구가 아니라 프로젝트의 결을 고르자.”