공지

Spring boot

12건

체크 예외를 던졌는데 회원 데이터가 롤백되지 않았다 - @Transactional 기본 롤백 정책과 rollbackFor

@Transactional을 붙여두면 메서드 안에서 예외가 터졌을 때 알아서 롤백해줄 거라고 막연히 믿고 있었다. 그런데 회원가입 로직에 정책 위반을 알리는 예외를 체크 예외(checked exception)로 만들어 던졌더니, 분명히 예외가 터졌는데도 회원 데이터가 그대로 커밋되어 있는 걸 발견했다.결론부터 말하면 @Transactional의 기본 롤백 규칙은 "예외가 터지면 무조건 롤백"이 아니라 "RuntimeException이나 Error가 터지면 롤백, 체크 예외는 롤백 안 함"이다. 이 글에서는 같은 회원가입 로직을 언체크 예외/체크 예외/rollbackFor 지정/rollbackFor 타입을 잘못 지정한 경우 네 가지로 나눠서 실제로 DB에 데이터가 남는지 직접 확인하고 왜 이렇게 동작하는지..

2026.07.10 · 댓글

@Transactional(readOnly = true)를 붙였더니 분명히 바꾼 값이 그대로 사라졌다 - 읽기 전용 트랜잭션과 Dirty Checking

조회 전용 메서드에는 @Transactional(readOnly = true)를 붙이라는 이야기를 많이 듣는다. 그런데 막상 이유를 물으면 "성능에 좋다더라" 정도로만 알고 넘어가는 경우가 많다. 나도 그랬다. 그래서 조회한 엔티티의 값을 실수로 바꿔놓고 저장까지 시켜버리는 버그가 있는 메서드에 readOnly = true를 붙이면 어떻게 되는지 직접 실험해봤다.결과부터 말하면, readOnly = true는 단순히 "이 메서드는 읽기만 한다"는 의미의 주석이 아니었다. 트랜잭션 안에서 조회한 엔티티의 필드를 바꿔도 커밋 시점에 저장이 안 됐고 save()를 명시적으로 다시 호출해도 마찬가지로 반영이 안 됐다. 반대로 새 엔티티를 저장하는 건 readOnly = true여도 정상으로 처리됐다. 여기서는 ..

2026.07.09 · 댓글

포인트 이력에서 회원 이름을 보려면 매번 따로 조회해야 했다 - @OneToMany 연관관계 매핑과 Jackson 무한 재귀

지난 글에서 회원가입할 때 웰컴 포인트를 같이 적립하도록 만들면서 PointHistory에 memberId라는 Long 컬럼을 하나 넣었다. 트랜잭션 경계를 확인하는 게 목적이라 이 정도로도 충분했는데, 막상 "이 포인트 이력이 누구 건지" 화면에 보여주려고 하니 문제가 생겼다. PointHistory 하나 가지고는 회원 이름도 이메일도 알 수 없고, 매번 memberId로 Member를 따로 조회해야 했다.결론만 이야기하면 이렇다. Long memberId는 그냥 숫자일 뿐이라 자바 코드 안에서 회원 객체로 바로 못 넘어간다. JPA의 @OneToMany/@ManyToOne으로 진짜 연관관계를 맺어주면 pointHistory.getMember().getName()처럼 객체 그래프를 그대로 타고 들어갈 ..

2026.07.08 · 댓글

회원가입은 됐는데 포인트가 안 쌓였다 - 서비스 계층 분리와 @Transactional 트랜잭션 경계

지금까지 만든 MemberController는 MemberRepository를 직접 호출하는 구조였다. 회원 하나 저장하는 정도는 이렇게 해도 문제가 없다. 그런데 "회원가입하면 웰컴 포인트 1000점을 같이 적립해준다"처럼 저장할 게 두 개로 늘어나면 이야기가 달라진다.결론만 이야기하면 이렇다. 컨트롤러에서 리포지토리 두 개를 순서대로 호출하면, 둘 중 하나가 실패해도 앞서 실행된 저장은 이미 커밋돼버릴 수 있다. 서비스 계층을 분리하고 @Transactional을 붙여야 "회원 저장 + 포인트 적립"이 하나의 단위로 묶여서 하나라도 실패하면 전부 롤백된다.말로만 하면 감이 잘 안 와서 일부러 실수 하나를 코드에 심어놓고 @Transactional 없이 실행해서 정말로 회원은 저장되고 포인트만 실패하는..

2026.07.07 · 댓글

Spring Data JPA findBy 쿼리 메서드로 조건 검색 만들기 — 메서드 이름만으로 SQL이 만들어지는 원리

JDK 21 LTS Spring Boot 3.3.4 MariaDB 10.11 MariaDB Connector/J 3.4.1 메서드 이름을 findByNameContaining처럼 정해진 규칙대로 지으면 Spring Data JPA가 SQL을 직접 만들어준다. 정확 일치·부분 일치·범위·정렬·조합·개수·존재 확인까지 6명의 실제 데이터로 검증했다. MariaDB의 LIKE는 기본적으로 대소문자를 구분하지 않는다는 것도 직접 확인했다.들어가며지난 글에서 JpaRepository를 상속하는 것만으로 저장·조회·수정·삭제가 전부 됐다. 그런데 "이름에 '길'이 들어간 회원만 찾고 싶다"거나 "나이가 25살 이상인 회원만 뽑고 싶다" 같은 조건은 JpaRepository가 기본으로 주는 메서드에 없다. f..

2026.07.06 · 댓글

Spring Boot에 MariaDB 연결하고 JPA로 첫 CRUD 만들기

들어가며지난 글에서 POST /members로 회원가입 API를 만들었다. 그런데 서버를 껐다 켜면 저장했던 회원이 전부 사라졌다. AtomicLong으로 id만 흉내 냈을 뿐, 진짜로 어딘가에 저장한 게 아니었기 때문이다.결론만 이야기하면 이렇다. MariaDB를 설치하고, Spring Data JPA로 Member 엔티티 하나를 만들면, 회원 저장·조회·수정·삭제가 전부 DB에 그대로 남는다. 서버를 껐다 켜도 데이터가 살아있는 것을 확인할 수 있다.curl -X POST http://localhost:8080/members \ -H "Content-Type: application/json" \ -d '{"name":"홍길동","email":"hong@example.com"}'{"id":1,"na..

2026.07.03 · 댓글

Spring Boot 첫 프로젝트 만들기 — start.spring.io 세팅부터 첫 GET API 실행까지

들어가며자바로 백엔드 개발을 시작하려는 사람에게 스프링 부트는 피할 수 없는 관문이다. 막상 시작하려니 어떤 버전을 골라야 하는지, IntelliJ는 어디서 내려받는지, Gradle 빌드 파일은 왜 두 종류인지, 물어볼 곳도 마땅치 않다.이 글에서는 PC에 JDK도 없는 상태에서 시작한다. 브라우저 주소창에 http://localhost:8080/hello를 쳤을 때 아래 JSON이 나오면 끝이다.{"message": "Hello, Spring Boot!"}설치 순서는 JDK → IntelliJ → 프로젝트 생성 → 코드 작성 → 실행, 딱 다섯 단계다.준비물 항목 버전 비고 JDK 21 LTS Eclipse Temur..

2026.06.30 · 댓글

[Spring Boot] Spring Security @PublicApi 어노테이션으로 공개 API 경로를 자동 관리하는 방법

들어가며Spring Security를 적용한 프로젝트를 운영하다 보면 어느 순간부터 SecurityConfig의 requestMatchers().permitAll() 목록이 길어지는 걸 느끼게 된다. 공개 API가 하나 늘 때마다 컨트롤러와 설정 파일, 두 곳을 동시에 수정해야 한다. 경로 하드코딩이 익숙해지면 나중에 경로가 바뀌었을 때 한 곳을 빠트리는 실수가 생기기 쉽다.이 글에서는 다음 두 가지 문제를 어노테이션으로 해결한 과정을 정리한다.경로 하드코딩 제거: 공개 API 경로를 SecurityConfig에 직접 적지 않고 컨트롤러 메서드에 어노테이션을 붙이는 것만으로 자동 등록되게 만든다.이중 방어 구조: 어노테이션 기반 수집이 주된 판별자 역할을 하고, SecurityConfig의 permitA..

2026.02.22 · 댓글 1

[MSA] API Gateway 구축하기 - Spring Boot + Spring Cloud Gateway

API Gateway를 구현하기 전에 Service Discovery Server가 필요한데 Netflix OSS Eureka를 사용한 구현하는 방법을 소개한 글을 읽고오면 된다. [MSA] Spring Boot로 Service Discovery 구축하기 - Netflix OSS Eureka Server 이전 글에서 이야기했듯이 MSA에서는 기본적으로 여러 서비스를 등록하고 등록한 서비스의 검색을 수행하는 서비스 디스커버리 서버(Service Discovery Server)가 필요하다. 디스커버리 서버 Client-Side diary-developer.tistory.com 바로 시작해보자! 1. API Gateway, Service 프로젝트 생성 1-1. Sping Cloud Gateway 프로젝트 생성..

2022.12.02 · 댓글

[Spring Boot] Java RESTful API 만들어서 GET, POST 호출 해보기

이전 글에서 이클립스(Eclipse)를 설치하고 Spring Boot 설정 및 프로젝트 생성까지 해봤는데 이번에는 Java, Gradle 빌드 기반으로 RESTful API를 한번 만들어 보겠다. 그전에 간략하게 REST란 무엇인가에 대한 설명을 하자면 REST REpresentational State Transfer의 약자로, 분산형 하이퍼미디어 시스템을 위한 아키텍처 REST 아키텍처의 구성요소 1. 자원 (Resource) - URI 모든 자원은 고유의 ID가 있고, HTTP URI로 표현한다. 클라이언트는 URI를 이용해서 자원을 지정하고 해당 자원을 조작하기 위해 서버로 요청한다. 2. 행위 (Verb) - Method HTTP 프로토콜의 Method를 사용하고 GET/POST/PUT/PATCH..

2022.12.01 · 댓글 2

[Spring Boot] 이클립스(Eclipse) 설치 및 스프링 부트(Spring Boot) 사용하기

개발을 시작하면서 가장 힘들었던 일 중 하나가 개발환경 세팅하기...😅 STS(Spring Tool Suite)를 설치하여 사용하는 방법도 있지만 이클립스를 직접 설치해서 Spring Boot를 사용하는 방법을 소개하려고 한다. 아래 내용들은 최신 버전 기준 Java 웹 개발 기준으로 작성되었다. 바로 시작!! 1. 이클립스(Eclipse) 설치 1-1. 이클립스 설치 파일 다운로드 아래 URL로 접속해서 최신 버전의 이클립스 설치를 해보자. Eclipse Downloads | The Eclipse Foundation The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 415 open source..

2022.11.30 · 댓글

킹반인이 사이드 프로젝트를 시작하다. (1)

킹반인이 사이드 프로젝트를 시작하다 (1) 나는 여느 사람과 달리 킹반인이라 평범하게 회사도 다니고 평범하게 일상도 즐기고 있는 와중에 문득 평범하게 내가 주도해서 개발을 하고 싶다는 생각을 하게 되었다. 혼자 개발하고 혼자 고민하고 이런 시간이 많다 보니 실력도 잘 늘지 않는 것 같기도 하고 많은 경험을 하지 못하는 것 같아서 여러 사람들과 프로젝트를 하면 좋겠다는 생각으로 이것저것 검색하기 시작했다. 검색해보면서 사이드 프로젝트라는 개념조차도 처음 알았는데...😅 너무 혼자만의 세상에 갇혀있었나 보다.. 따지고 보면 사이드 프로젝트가 이번이 완전 처음은 아니고 아는 사람들을 통해서 가볍게 프로젝트를 진행한 적이 있었는데, 회사에서 개발하면서 자바스크립트도 많이 만지게 되다 보니 스크립트가 궁금하여 바..

2022.11.16 · 댓글 5