<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>MyBatis on 얼쑤 · Team Edo</title><link>https://team-edo.github.io/tags/mybatis/</link><description>Recent content in MyBatis on 얼쑤 · Team Edo</description><generator>Hugo</generator><language>ko-kr</language><lastBuildDate>Mon, 02 Nov 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://team-edo.github.io/tags/mybatis/index.xml" rel="self" type="application/rss+xml"/><item><title>없는 행과 NULL 값 구분하기</title><link>https://team-edo.github.io/posts/2026/11/preserve-empty-record-and-cache-results/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/11/preserve-empty-record-and-cache-results/</guid><description>&lt;p>얼쑤는 녹음 파일이 없어도 연습 기록을 저장할 수 있습니다. 또 저장 뒤 악보 버전이 바뀌면 기록은 남지만 현재 악보에서 어느 칸에 해당하는지 표시하지 않습니다. 연습 기록 API를 만들면서 이렇게 값이 비는 경우를 두 곳에서 따로 처리했습니다. SQL을 읽는 매퍼와 한 요청 안에서 조회를 줄이는 캐시였습니다.&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>구분할 곳&lt;/th>
 &lt;th>항목이 없음&lt;/th>
 &lt;th>항목이 있고 값이 비어 있음&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>DB 조회&lt;/td>
 &lt;td>지울 세션이 없습니다.&lt;/td>
 &lt;td>세션은 지울 수 있고 녹음 파일은 없습니다.&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>요청 안의 캐시&lt;/td>
 &lt;td>악보 위치를 아직 조회하지 않았습니다.&lt;/td>
 &lt;td>이미 조회했고 현재 악보에서 표시할 위치가 없습니다.&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="녹음-파일이-없어도-지울-기록은-있다">녹음 없이도 남는 삭제 대상&lt;/h2>
&lt;p>삭제 API는 먼저 사용자가 지울 수 있는 기록인지 찾고, 녹음 경로가 있으면 파일 삭제도 처리합니다. 이때 &lt;code>recording_url&lt;/code>만 조회하면 MyBatis의 기본 설정에서는 조회한 열이 전부 NULL인 행이 &lt;code>null&lt;/code>로 반환됩니다. 결과만 보면 행이 없었는지, 행은 있는데 녹음 경로만 비었는지 구분할 수 없습니다.&lt;/p></description></item><item><title>Flyway를 끈 운영 프로필에서 API 켜기</title><link>https://team-edo.github.io/posts/2026/10/spring-profile-ops-terms-route/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/spring-profile-ops-terms-route/</guid><description>&lt;p>얼쑤의 백엔드는 운영에서 &lt;code>ops&lt;/code> 프로필로 실행했습니다. 이 프로필에서는 앱이 이미 만들어진 DB에 연결하고, 스키마 변경은 별도 작업에서 적용합니다. 업무 API를 켜기 전의 구성을 확인해 보니 약관을 비롯한 업무 컨트롤러와 서비스가 &lt;code>db&lt;/code> 프로필에만 등록돼 있었습니다. 프로세스가 기동해도 &lt;code>ops&lt;/code>로 뜬 컨텍스트에는 약관 요청을 받을 컨트롤러가 없었습니다.&lt;/p>
&lt;h2 id="업무-빈과-스키마-변경의-조건을-분리했다">업무 빈과 마이그레이션 분리&lt;/h2>
&lt;p>처음에는 두 프로필을 함께 켜면 업무 빈도 만들 수 있다고 생각했습니다. 하지만 당시 &lt;code>db&lt;/code>는 Flyway를 켰고 &lt;code>ops&lt;/code>는 껐습니다. 두 프로필에 같은 설정 키가 있으면 뒤에 지정한 프로필의 값이 적용됩니다. 순서를 바꾸는 것만으로 운영 앱이 기동할 때 마이그레이션을 실행할 수 있는 구성이었습니다.&lt;/p></description></item><item><title>JDBC로 바꾼 값을 MyBatis가 다시 읽지 못한 이유</title><link>https://team-edo.github.io/posts/2026/10/mybatis-session-cache-in-db-tests/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/mybatis-session-cache-in-db-tests/</guid><description>&lt;p>연습 세션에 분석 시도 번호와 시작 시각을 추가할 때 두 가지를 확인하려고 했습니다. 기존 행을 조회하면 새 필드에 기본값이 들어가야 하고, 값을 채운 행을 조회하면 매퍼가 새 필드를 올바르게 읽어야 했습니다. 처음에는 테스트 행 하나로 두 가지를 검사했습니다. MyBatis로 먼저 읽고 &lt;code>JdbcTemplate&lt;/code>로 값을 바꾼 뒤 같은 매퍼에서 다시 읽었습니다. 두 번째 조회에는 변경 전 시도 번호가 남아 있었습니다.&lt;/p>
&lt;h2 id="같은-sql을-다시-불러도-db까지-가지-않을-수-있다">세션 캐시가 재조회를 가로막은 이유&lt;/h2>
&lt;p>테스트는 Spring 트랜잭션 안에서 실행됐고, MyBatis는 같은 &lt;code>SqlSession&lt;/code>을 사용했습니다. MyBatis의 기본 로컬 캐시는 세션 안에서 같은 쿼리를 같은 인자로 요청하면 이전 결과를 재사용할 수 있습니다. 매퍼의 갱신은 이 캐시를 비우지만, 여기서 값을 바꾼 것은 &lt;code>JdbcTemplate&lt;/code>였습니다. 같은 트랜잭션에서 SQL을 실행했어도 MyBatis가 자신의 캐시에 있는 조회 결과를 무효화할 계기는 없었습니다.&lt;/p></description></item></channel></rss>