<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Spring on 얼쑤 · Team Edo</title><link>https://team-edo.github.io/tags/spring/</link><description>Recent content in Spring on 얼쑤 · Team Edo</description><generator>Hugo</generator><language>ko-kr</language><lastBuildDate>Sun, 08 Nov 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://team-edo.github.io/tags/spring/index.xml" rel="self" type="application/rss+xml"/><item><title>Spring 테스트 53개 실패와 MySQL 연결 한도</title><link>https://team-edo.github.io/posts/2026/11/spring-test-mysql-connections/</link><pubDate>Sun, 08 Nov 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/11/spring-test-mysql-connections/</guid><description>&lt;p>얼쑤 백엔드의 &lt;code>databaseTest&lt;/code>는 Spring 애플리케이션과 실제 MySQL을 연결해 실행하는 통합 테스트입니다. 앞선 실행에서 161개가 모두 통과했는데, 다른 변경을 병합한 뒤에는 174개 중 53개가 실패했습니다. 서로 다른 기능을 확인하는 테스트에서 같은 메시지가 45번 나왔습니다. &lt;code>Too many connections&lt;/code>였습니다.&lt;/p>
&lt;h2 id="실패한-테스트보다-먼저-연결을-확인했다">테스트보다 먼저 연결 확인&lt;/h2>
&lt;p>Spring 테스트가 애플리케이션 컨텍스트를 올리는 도중 DB에 연결하지 못하면 테스트 코드까지 실행되지 못합니다. 같은 설정의 컨텍스트를 여는 데 이미 실패한 뒤에는 Spring이 다음 로딩 시도를 건너뛰면서 &lt;code>ApplicationContext failure threshold exceeded&lt;/code>를 남길 수 있습니다. 이 메시지만 보면 원인이 비슷한 실패가 여러 개 생긴 것처럼 보입니다. 앞선 로딩 실패의 예외까지 내려가면 MySQL이 새 연결을 거부했다는 단서가 나옵니다. &lt;a href="https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/ctx-management/failure-threshold.html">Spring의 컨텍스트 로딩 실패 정책&lt;/a> · &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/too-many-connections.html">MySQL의 연결 초과 오류&lt;/a>&lt;/p></description></item><item><title>업무 결과를 HTTP 응답으로 바꾸기</title><link>https://team-edo.github.io/posts/2026/10/map-use-case-results-to-http/</link><pubDate>Thu, 29 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/map-use-case-results-to-http/</guid><description>&lt;p>연주 평가를 조회하는 요청은 평가가 있는지, 다른 회원의 세션인지, 아직 분석 중인지에 따라 답이 달라집니다. 분석을 다시 요청할 때도 아직 작업을 시작할 수 없는 경우가 여러 가지입니다. 두 기능에서 예상되는 업무 결과를 이름 있는 값으로 표현하고, HTTP 상태와 응답 본문은 컨트롤러에서 정했습니다.&lt;/p>
&lt;h2 id="평가-조회는-누가-무엇을-판단하는가">평가 조회의 판단 경계&lt;/h2>
&lt;p>컨트롤러는 인증을 마친 토큰에서 회원 ID를 읽어 세션 ID와 함께 넘깁니다. 유스케이스는 조회 계약을 통해 소유한 세션을 찾고, 완료된 세션에서만 평가와 음표 결과를 읽습니다. 세션과 음표 결과는 같은 읽기 전용 트랜잭션에서 조회합니다. 그 계약을 구현한 MyBatis 어댑터는 조회 행을 업무 코드가 읽을 값으로 바꿉니다.&lt;/p></description></item><item><title>트랜잭션 커밋 경계 테스트</title><link>https://team-edo.github.io/posts/2026/10/test-transaction-commit-boundary/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/test-transaction-commit-boundary/</guid><description>&lt;p>연주 분석에는 트랜잭션이 끝나는 시점이 중요한 일이 두 가지 있습니다. 분석 결과를 기록할 때는 세션 상태와 평가를 함께 저장합니다. 녹음이 올라왔을 때는 업로드가 확정된 뒤에만 분석을 시작합니다. 둘 다 오류를 던지는지만 확인하면, 앞서 실행한 쓰기나 바깥에 넘긴 작업이 남았는지 알 수 없습니다.&lt;/p>
&lt;h2 id="db에-실제로-남는-값을-읽었다">롤백 뒤 남은 DB 상태 확인&lt;/h2>
&lt;p>보통 매퍼 테스트는 테스트에 트랜잭션을 열어 두고 끝에서 한꺼번에 되돌립니다. 결과 저장의 원자성 검사에서는 테스트 트랜잭션을 열지 않았습니다. 테스트가 서비스 트랜잭션의 커밋 경계를 대신하면, 서비스를 벗어난 뒤에도 무엇이 남는지 구분하기 어렵기 때문입니다.&lt;/p></description></item><item><title>형식이 맞는 날짜가 500을 낸 이유</title><link>https://team-edo.github.io/posts/2026/10/reject-out-of-range-calendar-dates/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/reject-out-of-range-calendar-dates/</guid><description>&lt;p>얼쑤의 연습 통계 API는 시작일과 종료일을 받아 해당 기간의 연습 시간과 횟수를 돌려줍니다. 요약 API는 바로 앞 기간의 통계도 함께 제공합니다. 두 날짜를 Spring의 &lt;code>@DateTimeFormat(iso = ISO.DATE)&lt;/code>로 받아 &lt;code>LocalDate&lt;/code>로 변환했습니다. 그러면 &lt;code>2026/10/01&lt;/code>처럼 형식이 어긋난 날짜는 컨트롤러가 실행되기 전에 400으로 거절됩니다.&lt;/p>
&lt;p>리뷰에서 날짜 형식 검사를 통과하는 값이 500을 냈습니다. 요약 API에 시작일과 종료일을 모두 **&lt;code>-999999999-01-01&lt;/code>**로 보내면 두 값은 &lt;code>LocalDate&lt;/code>로 변환됐습니다. 길이도 하루여서 기존 기간 제한을 통과했습니다. 직전 기간을 구하려고 시작일에서 하루를 빼는 순간 &lt;code>LocalDate&lt;/code>의 범위를 벗어났고, &lt;code>DateTimeException&lt;/code>이 500으로 이어졌습니다.&lt;/p></description></item></channel></rss>