[{"data":1,"prerenderedAt":4697},["ShallowReactive",2],{"navigation_docs_ko":3,"-ko-note-spring-spring-persistence-context":267,"-ko-note-spring-spring-persistence-context-surround":4692},[4,130,253],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":33},"Note (개발 지식)","emojione-v1:note-pad","\u002Fko\u002Fnote","ko\u002F1.note",[10,34,48,74,84,94,110,120],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":33},"Spring","logos:spring-icon","\u002Fko\u002Fnote\u002Fspring","ko\u002F1.note\u002F0.spring",[16,21,25,29],{"title":17,"path":18,"stem":19,"icon":20},"Spring AI 핵심 개념과 LLM 애플리케이션 구조 이해","\u002Fko\u002Fnote\u002Fspring\u002Fspring-ai","ko\u002F1.note\u002F0.spring\u002F1.spring-ai","lucide:file-text",{"title":22,"path":23,"stem":24,"icon":20},"[Java] Record와 @Version으로 이해하는 불변 데이터와 동시성 제어","\u002Fko\u002Fnote\u002Fspring\u002Frecord-and-version-concurrency","ko\u002F1.note\u002F0.spring\u002F2.record-and-version-concurrency",{"title":26,"path":27,"stem":28,"icon":20},"[JPA] @PersistenceContext와 EntityManager로 이해하는 영속성 컨텍스트","\u002Fko\u002Fnote\u002Fspring\u002Fspring-persistence-context","ko\u002F1.note\u002F0.spring\u002F3.spring-persistence-context",{"title":30,"path":31,"stem":32,"icon":20},"[Java] YearMonth로 월 단위 날짜를 다루는 방법","\u002Fko\u002Fnote\u002Fspring\u002Fjava-year-month","ko\u002F1.note\u002F0.spring\u002F4.java-year-month",false,{"title":35,"icon":36,"path":37,"stem":38,"children":39,"page":33},"Javascript","skill-icons:javascript","\u002Fko\u002Fnote\u002Fjavascript","ko\u002F1.note\u002F1.javascript",[40,44],{"title":41,"path":42,"stem":43,"icon":20},"Promise.all과 구조 분해 할당을 활용한 데이터 처리 패턴","\u002Fko\u002Fnote\u002Fjavascript\u002Fdestructuring","ko\u002F1.note\u002F1.javascript\u002F1.destructuring",{"title":45,"path":46,"stem":47,"icon":20},"JavaScript 배열 고차 함수와 데이터 처리 패턴 이해","\u002Fko\u002Fnote\u002Fjavascript\u002Ffilter","ko\u002F1.note\u002F1.javascript\u002F2.filter",{"title":49,"icon":50,"path":51,"stem":52,"children":53,"page":33},"Nuxt4","logos:nuxt-icon","\u002Fko\u002Fnote\u002Fnuxt4","ko\u002F1.note\u002F2.nuxt4",[54,58,62,66,70],{"title":55,"path":56,"stem":57,"icon":20},"Nuxt 4를 선택한 이유와 아키텍처 및 실무 가이드","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-info","ko\u002F1.note\u002F2.nuxt4\u002F1.nuxt-info",{"title":59,"path":60,"stem":61,"icon":20},"Nuxt useAsyncData 동작 원리와 SSR 데이터 페칭 최적화","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-use_async_data","ko\u002F1.note\u002F2.nuxt4\u002F2.nuxt-use_async_data",{"title":63,"path":64,"stem":65,"icon":20},"Nuxt Content v3 데이터 모델과 Query 시스템 이해","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-content-v3","ko\u002F1.note\u002F2.nuxt4\u002F3.nuxt-content-v3",{"title":67,"path":68,"stem":69,"icon":20},"Nuxt Auto-imports 내부 동작과 컴파일 과정 분석","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-auto-import","ko\u002F1.note\u002F2.nuxt4\u002F4.nuxt-auto-import",{"title":71,"path":72,"stem":73,"icon":20},"Nuxt 렌더링 방식 이해: SSR, SSG, ISR, CSR 구현 방법","\u002Fko\u002Fnote\u002Fnuxt4\u002Fnuxt-rendering-strategy","ko\u002F1.note\u002F2.nuxt4\u002F5.nuxt-rendering-strategy",{"title":75,"icon":76,"path":77,"stem":78,"children":79,"page":33},"Nitro","unjs:nitro","\u002Fko\u002Fnote\u002Fnitro","ko\u002F1.note\u002F3.nitro",[80],{"title":81,"path":82,"stem":83,"icon":20},"Nitro 아키텍처와 서버 엔진 구조","\u002Fko\u002Fnote\u002Fnitro\u002Fnitro","ko\u002F1.note\u002F3.nitro\u002Fnitro",{"title":85,"icon":86,"path":87,"stem":88,"children":89,"page":33},"Devops","vscode-icons:file-type-pipeline","\u002Fko\u002Fnote\u002Fdevops","ko\u002F1.note\u002F4.devops",[90],{"title":91,"path":92,"stem":93,"icon":20},"서버사이드 WebAssembly(Wasm)와 차세대 실행 환경","\u002Fko\u002Fnote\u002Fdevops\u002Fwebassembly","ko\u002F1.note\u002F4.devops\u002F1.webAssembly",{"title":95,"icon":96,"path":97,"stem":98,"children":99,"page":33},"Tooling","lucide:wrench","\u002Fko\u002Fnote\u002Ftooling","ko\u002F1.note\u002F4.tooling",[100],{"title":101,"icon":102,"path":103,"stem":104,"children":105,"page":33},"Package Manager","devicon:npm","\u002Fko\u002Fnote\u002Ftooling\u002Fpackage-manager","ko\u002F1.note\u002F4.tooling\u002F1.package-manager",[106],{"title":107,"path":108,"stem":109,"icon":20},"Package Lock 파일의 역할과 의존성 관리 원리","\u002Fko\u002Fnote\u002Ftooling\u002Fpackage-manager\u002Fpackage-lock","ko\u002F1.note\u002F4.tooling\u002F1.package-manager\u002F1.package-lock",{"title":111,"icon":112,"path":113,"stem":114,"children":115,"page":33},"Web","streamline-plump:web","\u002Fko\u002Fnote\u002Fweb","ko\u002F1.note\u002F4.web",[116],{"title":117,"path":118,"stem":119,"icon":20},"웹 애플리케이션 렌더링 아키텍처 이해","\u002Fko\u002Fnote\u002Fweb\u002Frendering-modes","ko\u002F1.note\u002F4.web\u002F2.rendering-modes",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":33},"SEO","icon-park-solid:seo","\u002Fko\u002Fnote\u002Fseo","ko\u002F1.note\u002F6.seo",[126],{"title":127,"path":128,"stem":129,"icon":20},"[SEO] 개발 블로그 검색 노출을 위한 robots.txt와 SEO 설정 가이드","\u002Fko\u002Fnote\u002Fseo\u002Fseo","ko\u002F1.note\u002F6.seo\u002F1.seo",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":33},"Project (개발일지)","icon-park-solid:branch-two","\u002Fko\u002Fproject","ko\u002F2.project",[136,187],{"title":137,"icon":138,"path":139,"stem":140,"children":141,"page":33},"Brolog","custom:symbol","\u002Fko\u002Fproject\u002Fbrolog","ko\u002F2.project\u002F1.brolog",[142,146,150,154,158,162,166,170,174,179,183],{"title":143,"path":144,"stem":145,"icon":20},"[Brolog] 프로젝트 개요","\u002Fko\u002Fproject\u002Fbrolog\u002Foutline","ko\u002F2.project\u002F1.brolog\u002F1.outline",{"title":147,"path":148,"stem":149,"icon":20},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (3) - Runtime 기능 문제 분석과 AI Assistant 전환","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy3-ai-integration","ko\u002F2.project\u002F1.brolog\u002F10.vercel-deploy3-ai-integration",{"title":151,"path":152,"stem":153,"icon":20},"[Brolog] AI Assistant 적용 과정 - Agent 구조와 API 사용량 관리 시 고려사항","\u002Fko\u002Fproject\u002Fbrolog\u002Fai-assistant-application-process","ko\u002F2.project\u002F1.brolog\u002F11.ai-assistant-application-process",{"title":155,"path":156,"stem":157,"icon":20},"[Brolog] 검색 엔진 노출을 위한 SEO 적용 과정","\u002Fko\u002Fproject\u002Fbrolog\u002Fbrolog-seo","ko\u002F2.project\u002F1.brolog\u002F12.brolog-seo",{"title":159,"path":160,"stem":161,"icon":20},"[Brolog] 프로젝트 구조","\u002Fko\u002Fproject\u002Fbrolog\u002Fstructure","ko\u002F2.project\u002F1.brolog\u002F2.structure",{"title":163,"path":164,"stem":165,"icon":20},"[Brolog] Nuxt Content 네비게이션 아이콘 커스텀 빌드","\u002Fko\u002Fproject\u002Fbrolog\u002Fcustom-icon","ko\u002F2.project\u002F1.brolog\u002F3.custom-icon",{"title":167,"path":168,"stem":169,"icon":20},"[Brolog] Nuxt4 Auto-imports 동작 원리와 자동 import 시스템 이해","\u002Fko\u002Fproject\u002Fbrolog\u002Fnuxt-auto-import","ko\u002F2.project\u002F1.brolog\u002F4.nuxt-auto-import",{"title":171,"path":172,"stem":173,"icon":20},"[Brolog] 개발 블로그 메인 페이지 구현","\u002Fko\u002Fproject\u002Fbrolog\u002Fdevelop-main","ko\u002F2.project\u002F1.brolog\u002F5.develop-main",{"title":175,"path":176,"stem":177,"icon":178},"[Brolog] 브랜드 아이덴티티 적용 - Custom 404 페이지와 Default No Image 구현","\u002Fko\u002Fproject\u002Fbrolog\u002Fcustom-error-and-default-thumbnail","ko\u002F2.project\u002F1.brolog\u002F6.custom-error-and-default-thumbnail","lucide:image",{"title":180,"path":181,"stem":182,"icon":20},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (1)","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy1","ko\u002F2.project\u002F1.brolog\u002F8.vercel-deploy1",{"title":184,"path":185,"stem":186,"icon":20},"[Brolog] Nuxt Multi Layer 프로젝트 Vercel 배포 (2) - Build Pipeline 오류 분석과 Nuxt 실행 구조 이해","\u002Fko\u002Fproject\u002Fbrolog\u002Fvercel-deploy2-error-analyze","ko\u002F2.project\u002F1.brolog\u002F9.vercel-deploy2-error-analyze",{"title":188,"icon":189,"path":190,"stem":191,"children":192,"page":33},"Brobean","custom:brobean","\u002Fko\u002Fproject\u002Fbrobean","ko\u002F2.project\u002F2.brobean",[193,197,201,205,209,213,217,221,225,229,233,237,241,245,249],{"title":194,"path":195,"stem":196,"icon":20},"[BroBean] 연인과 함께 사용하는 가계부: BroBean - 프로젝트 기획과 이름의 탄생","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-01","ko\u002F2.project\u002F2.brobean\u002F1.brobean-dev-log-01",{"title":198,"path":199,"stem":200,"icon":20},"[BroBean] 연인과 함께 사용하는 가계부: BroBean 프로젝트 시작 - Nuxt 4 기반 프론트 개발 환경 구축","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-02","ko\u002F2.project\u002F2.brobean\u002F2.brobean-dev-log-02",{"title":202,"path":203,"stem":204,"icon":20},"[BroBean] BroBean 프로젝트 #3 - 모바일 앱 전환을 고려한 공통 레이아웃 설계","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-03","ko\u002F2.project\u002F2.brobean\u002F3.brobean-dev-log-03",{"title":206,"path":207,"stem":208,"icon":20},"[BroBean] BroBean 프로젝트 #4 - 홈 화면(Dashboard) 설계와 Mock 데이터 구성","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-04","ko\u002F2.project\u002F2.brobean\u002F4.brobean-dev-log-04",{"title":210,"path":211,"stem":212,"icon":20},"[BroBean] BroBean 프로젝트 #5 돈을 모으면 캐릭터도 성장한다 - 브로빈 성장 시스템 설계","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-05","ko\u002F2.project\u002F2.brobean\u002F5.brobean-dev-log-05",{"title":214,"path":215,"stem":216,"icon":20},"[BroBean] BroBean 프로젝트 #6 씨앗 심기와 밭 가꾸기 기능 설계","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-06","ko\u002F2.project\u002F2.brobean\u002F6.brobean-dev-log-06",{"title":218,"path":219,"stem":220,"icon":20},"[BroBean] BroBean 프로젝트 #7 성장 일지와 나무 키우기 화면 구현","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-07","ko\u002F2.project\u002F2.brobean\u002F7.brobean-dev-log-07",{"title":222,"path":223,"stem":224,"icon":20},"[BroBean] BroBean 프로젝트 #8 수확 정산으로 한눈에 보는 소비 흐름 - 소비 리포트 & 정산 화면 구현","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-08","ko\u002F2.project\u002F2.brobean\u002F8.brobean-dev-log-08",{"title":226,"path":227,"stem":228,"icon":20},"[BroBean] BroBean 프로젝트 #9 알림부터 마이페이지까지 - 사용자 편의 기능과 개인 농장 설정 화면 구현","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-09","ko\u002F2.project\u002F2.brobean\u002F9.brobean-dev-log-09",{"title":230,"path":231,"stem":232,"icon":20},"[BroBean] BroBean 프로젝트 #10 로그인부터 파트너 초대까지 - 계정 인증과 커플 연결 화면 구현","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-10","ko\u002F2.project\u002F2.brobean\u002F910.brobean-dev-log-10",{"title":234,"path":235,"stem":236,"icon":20},"[BroBean] BroBean 프로젝트 #11 개인과 커플을 모두 위한 모드 분리 - Pinia 기반 개인\u002F커플 모드 전환 구현","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-11","ko\u002F2.project\u002F2.brobean\u002F911.brobean-dev-log-11",{"title":238,"path":239,"stem":240,"icon":20},"[BroBean] BroBean 프로젝트 #12 인증 상태 복구와 Nuxt Plugin 실행 순서 제어","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-12","ko\u002F2.project\u002F2.brobean\u002F912.brobean-dev-log-12",{"title":242,"path":243,"stem":244,"icon":20},"[BroBean] BroBean 프로젝트 #13 개인·커플 모드와 가계부 API 구현 - 쿼리 성능을 다시 돌아보다","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-13","ko\u002F2.project\u002F2.brobean\u002F913.brobean-dev-log-13",{"title":246,"path":247,"stem":248,"icon":20},"[BroBean] BroBean 프로젝트 #14 순환 참조 오류를 ObjectProvider로 해결하기","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-14","ko\u002F2.project\u002F2.brobean\u002F914.brobean-dev-log-14",{"title":250,"path":251,"stem":252,"icon":20},"[BroBean] BroBean 프로젝트 #15 JPA 페이지네이션 적용, Page와 Slice의 차이","\u002Fko\u002Fproject\u002Fbrobean\u002Fbrobean-dev-log-15","ko\u002F2.project\u002F2.brobean\u002F915.brobean-dev-log-15",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":33},"Error (트러블슈팅)","emojione:stop-sign","\u002Fko\u002Ftrouble-shooting","ko\u002F3.trouble-shooting",[259],{"title":137,"icon":138,"path":260,"stem":261,"children":262,"page":33},"\u002Fko\u002Ftrouble-shooting\u002Fbrolog","ko\u002F3.trouble-shooting\u002F1.brolog",[263],{"title":264,"path":265,"stem":266,"icon":20},"[Nuxt Content] Nuxt Icon 오류 해결과 Custom Collection 기반 오프라인 아이콘 구성","\u002Fko\u002Ftrouble-shooting\u002Fbrolog\u002Fnuxt-icon-restricted-network-troubleshooting","ko\u002F3.trouble-shooting\u002F1.brolog\u002F1.nuxt-icon-restricted-network-troubleshooting",{"id":268,"title":26,"body":269,"date":4674,"description":4675,"extension":4676,"links":4677,"meta":4678,"navigation":4687,"path":27,"seo":4688,"stem":28,"__hash__":4691},"docs_ko\u002Fko\u002F1.note\u002F0.spring\u002F3.spring-persistence-context.md",{"type":270,"value":271,"toc":4672},"minimark",[272,4668],[273,274,276,281,285,324,327,336,339,354,357,360,368,371,374,442,445,449,457,460,525,528,539,542,551,554,560,563,565,569,575,582,585,665,668,706,709,712,733,736,756,759,762,768,771,773,777,780,786,789,809,812,819,821,825,830,833,840,843,846,881,884,887,893,896,902,908,911,913,917,920,923,929,936,938,942,948,950,1013,1015,1021,1024,1027,1033,1036,1042,1045,1047,1051,1056,1059,1119,1122,1138,1144,1147,1150,1157,1160,1163,1165,1169,1172,1175,1181,1184,1186,1190,1193,1225,1231,1234,1240,1243,1246,1248,1252,1255,1300,1303,1309,1312,1315,1318,1320,1324,1327,1359,1362,1364,1370,1372,1374,1378,1381,1384,1404,1407,1424,1427,1430,1436,1438,1441,1443,1447,1450,1468,1471,1474,1477,1483,1485,1489,1492,1578,1581,1583,1587,1590,1634,1637,1643,1646,1655,1658,1660,1666,1669,1671,1675,1680,1683,1688,1691,1693,1790,1793,1813,1815,1835,1838,1841,1843,1847,1850,1853,1859,1862,1864,1887,1890,1892,1896,1903,1905,1960,1966,1969,2025,2028,2030,2036,2039,2041,2045,2051,2054,2061,2063,2065,2087,2090,2093,2099,2101,2103,2107,2110,2113,2119,2122,2125,2131,2134,2137,2139,2143,2146,2149,2155,2158,2161,2163,2291,2294,2296,2300,2303,2306,2399,2402,2408,2415,2417,2421,2424,2444,2447,2454,2457,2483,2486,2492,2498,2501,2503,2507,2510,2516,2519,2522,2542,2545,2548,2551,2571,2573,2661,2664,2666,2670,2676,2696,2701,2707,2710,2717,2723,2725,2731,2734,2740,2766,2768,2772,2778,2781,2871,2874,2876,2882,2885,2887,2891,2894,2933,2936,2956,2959,3017,3020,3023,3025,3031,3034,3040,3042,3046,3049,3052,3058,3061,3064,3090,3093,3095,3099,3102,3188,3191,3194,3218,3221,3223,3229,3232,3234,3238,3241,3243,3329,3335,3338,3360,3363,3366,3404,3407,3410,3412,3416,3419,3422,3437,3440,3442,3505,3508,3510,3516,3519,3525,3527,3531,3534,3556,3559,3579,3582,3585,3593,3600,3602,3608,3614,3617,3620,3622,3626,3629,3836,3839,3981,3987,3990,3996,3999,4001,4005,4008,4010,4091,4094,4097,4115,4118,4121,4132,4135,4137,4141,4144,4249,4252,4258,4261,4263,4267,4272,4275,4281,4283,4303,4306,4311,4314,4319,4322,4324,4328,4331,4365,4367,4421,4424,4427,4430,4433,4439,4442,4444,4448,4451,4460,4463,4466,4472,4475,4481,4483,4487,4492,4512,4515,4518,4524,4532,4541,4544,4550,4552,4558,4560,4566,4569,4575,4616,4619,4625,4628,4634,4641,4643,4646,4652,4655,4661,4663],"u-page-card",{":spotlight":275},"true",[277,278,280],"h1",{"id":279},"persistencecontext와-entitymanager로-이해하는-jpa-영속성-컨텍스트","📖 @PersistenceContext와 EntityManager로 이해하는 JPA 영속성 컨텍스트",[282,283,284],"p",{},"Spring Boot에서 JPA를 사용하다 보면 다음과 같은 코드를 마주치는 경우가 있다.",[286,287,292],"pre",{"className":288,"code":289,"language":290,"meta":291,"style":291},"language-java shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","@PersistenceContext\nprivate EntityManager entityManager;\n","java","",[293,294,295,308],"code",{"__ignoreMap":291},[296,297,300,304],"span",{"class":298,"line":299},"line",1,[296,301,303],{"class":302},"sMK4o","@",[296,305,307],{"class":306},"spNyl","PersistenceContext\n",[296,309,311,314,317,321],{"class":298,"line":310},2,[296,312,313],{"class":306},"private",[296,315,316],{"class":306}," EntityManager",[296,318,320],{"class":319},"sTEyZ"," entityManager",[296,322,323],{"class":302},";\n",[282,325,326],{},"처음 보면 단순히:",[328,329,330],"blockquote",{},[282,331,332,335],{},[293,333,334],{},"EntityManager","를 주입받는 어노테이션인가?",[282,337,338],{},"정도로 생각하기 쉽다.",[282,340,341,342,345,346,350,351,353],{},"실제로 결과만 보면 맞는 말이지만, ",[293,343,344],{},"@PersistenceContext","를 제대로 이해하려면 그 뒤에 있는 ",[347,348,349],"strong",{},"영속성 컨텍스트(Persistence Context)"," 와 ",[347,352,334],{},"의 관계를 함께 이해해야 한다.",[282,355,356],{},"JPA에서 엔티티를 조회하고 수정하고 저장하는 과정은 단순히 데이터베이스에 SQL을 실행하는 구조가 아니다.",[282,358,359],{},"대략적으로:",[286,361,366],{"className":362,"code":364,"language":365,"meta":291},[363],"language-text","EntityManager\n      │\n      ▼\n영속성 컨텍스트\n      │\n      ▼\nEntity 상태 관리\n      │\n      ├── 조회\n      ├── 변경 감지\n      ├── 1차 캐시\n      └── Flush\n             │\n             ▼\n          Database\n","text",[293,367,364],{"__ignoreMap":291},[282,369,370],{},"와 같은 구조로 동작한다.",[282,372,373],{},"이번 글에서는 다음 내용을 중심으로 정리해본다.",[375,376,377,383,388,391,399,402,405,408,411,414,417,433,436],"ul",{},[378,379,380,382],"li",{},[293,381,344],{},"란 무엇인가",[378,384,385,387],{},[293,386,334],{},"는 어떤 역할을 하는가",[378,389,390],{},"영속성 컨텍스트란 무엇인가",[378,392,393,395,396,398],{},[293,394,344],{},"와 ",[293,397,334],{},"의 관계",[378,400,401],{},"엔티티의 생명주기",[378,403,404],{},"1차 캐시",[378,406,407],{},"동일성 보장",[378,409,410],{},"Dirty Checking",[378,412,413],{},"Flush란 무엇인가",[378,415,416],{},"Transaction과 영속성 컨텍스트의 관계",[378,418,419,422,423,422,426,422,429,432],{},[293,420,421],{},"persist()",", ",[293,424,425],{},"find()",[293,427,428],{},"remove()",[293,430,431],{},"merge()","의 차이",[378,434,435],{},"Spring Data JPA에서는 왜 직접 사용할 일이 적은가",[378,437,438,439,441],{},"실무에서 ",[293,440,334],{},"를 직접 사용하는 경우",[443,444],"hr",{},[277,446,448],{"id":447},"_1-persistencecontext란-무엇인가","🔎 1. @PersistenceContext란 무엇인가?",[282,450,451,453,454,456],{},[293,452,344],{},"는 JPA의 ",[293,455,334],{},"를 주입받기 위해 사용하는 어노테이션이다.",[282,458,459],{},"가장 기본적인 사용 형태는 다음과 같다.",[286,461,463],{"className":288,"code":462,"language":290,"meta":291,"style":291},"@Repository\npublic class UserRepository {\n\n    @PersistenceContext\n    private EntityManager entityManager;\n\n}\n",[293,464,465,472,487,494,502,514,519],{"__ignoreMap":291},[296,466,467,469],{"class":298,"line":299},[296,468,303],{"class":302},[296,470,471],{"class":306},"Repository\n",[296,473,474,477,480,484],{"class":298,"line":310},[296,475,476],{"class":306},"public",[296,478,479],{"class":306}," class",[296,481,483],{"class":482},"sBMFI"," UserRepository",[296,485,486],{"class":302}," {\n",[296,488,490],{"class":298,"line":489},3,[296,491,493],{"emptyLinePlaceholder":492},true,"\n",[296,495,497,500],{"class":298,"line":496},4,[296,498,499],{"class":302},"    @",[296,501,307],{"class":306},[296,503,505,508,510,512],{"class":298,"line":504},5,[296,506,507],{"class":306},"    private",[296,509,316],{"class":306},[296,511,320],{"class":319},[296,513,323],{"class":302},[296,515,517],{"class":298,"line":516},6,[296,518,493],{"emptyLinePlaceholder":492},[296,520,522],{"class":298,"line":521},7,[296,523,524],{"class":302},"}\n",[282,526,527],{},"여기서 중요한 것은:",[286,529,531],{"className":288,"code":530,"language":290,"meta":291,"style":291},"@PersistenceContext\n",[293,532,533],{"__ignoreMap":291},[296,534,535,537],{"class":298,"line":299},[296,536,303],{"class":302},[296,538,307],{"class":306},[282,540,541],{},"자체가 데이터베이스 연결 객체를 만들어주는 것은 아니라는 점이다.",[282,543,544,546,547,550],{},[293,545,344],{},"는 ",[347,548,549],{},"JPA가 관리하는 EntityManager를 현재 컴포넌트에 주입해달라는 의미","에 가깝다.",[282,552,553],{},"즉:",[286,555,558],{"className":556,"code":557,"language":365,"meta":291},[363],"@PersistenceContext\n\n↓\n\nEntityManager 주입\n\n↓\n\n영속성 컨텍스트와 상호작용\n\n↓\n\nEntity 상태 관리\n\n↓\n\nDatabase 반영\n",[293,559,557],{"__ignoreMap":291},[282,561,562],{},"이라는 흐름으로 이해하면 된다.",[443,564],{},[277,566,568],{"id":567},"_2-entitymanager란-무엇인가","🧩 2. EntityManager란 무엇인가?",[282,570,571,572,574],{},"그렇다면 ",[293,573,334],{},"는 무엇일까?",[282,576,577,578,581],{},"EntityManager는 이름 그대로 ",[347,579,580],{},"JPA에서 엔티티를 관리하는 핵심 인터페이스","다.",[282,583,584],{},"예를 들어 다음과 같은 엔티티가 있다고 하자.",[286,586,588],{"className":288,"code":587,"language":290,"meta":291,"style":291},"@Entity\npublic class User {\n\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    private String name;\n\n}\n",[293,589,590,597,608,612,619,626,638,642,655,660],{"__ignoreMap":291},[296,591,592,594],{"class":298,"line":299},[296,593,303],{"class":302},[296,595,596],{"class":306},"Entity\n",[296,598,599,601,603,606],{"class":298,"line":310},[296,600,476],{"class":306},[296,602,479],{"class":306},[296,604,605],{"class":482}," User",[296,607,486],{"class":302},[296,609,610],{"class":298,"line":489},[296,611,493],{"emptyLinePlaceholder":492},[296,613,614,616],{"class":298,"line":496},[296,615,499],{"class":302},[296,617,618],{"class":306},"Id\n",[296,620,621,623],{"class":298,"line":504},[296,622,499],{"class":302},[296,624,625],{"class":306},"GeneratedValue\n",[296,627,628,630,633,636],{"class":298,"line":516},[296,629,507],{"class":306},[296,631,632],{"class":306}," Long",[296,634,635],{"class":319}," id",[296,637,323],{"class":302},[296,639,640],{"class":298,"line":521},[296,641,493],{"emptyLinePlaceholder":492},[296,643,645,647,650,653],{"class":298,"line":644},8,[296,646,507],{"class":306},[296,648,649],{"class":306}," String",[296,651,652],{"class":319}," name",[296,654,323],{"class":302},[296,656,658],{"class":298,"line":657},9,[296,659,493],{"emptyLinePlaceholder":492},[296,661,663],{"class":298,"line":662},10,[296,664,524],{"class":302},[282,666,667],{},"EntityManager를 사용하면:",[286,669,671],{"className":288,"code":670,"language":290,"meta":291,"style":291},"entityManager.find(User.class, 1L);\n",[293,672,673],{"__ignoreMap":291},[296,674,675,678,681,685,688,691,693,696,699,703],{"class":298,"line":299},[296,676,677],{"class":319},"entityManager",[296,679,680],{"class":302},".",[296,682,684],{"class":683},"s2Zo4","find",[296,686,687],{"class":302},"(",[296,689,690],{"class":319},"User",[296,692,680],{"class":302},[296,694,695],{"class":319},"class",[296,697,698],{"class":302},",",[296,700,702],{"class":701},"sbssI"," 1L",[296,704,705],{"class":302},");\n",[282,707,708],{},"처럼 엔티티를 조회할 수 있다.",[282,710,711],{},"또한:",[286,713,715],{"className":288,"code":714,"language":290,"meta":291,"style":291},"entityManager.persist(user);\n",[293,716,717],{"__ignoreMap":291},[296,718,719,721,723,726,728,731],{"class":298,"line":299},[296,720,677],{"class":319},[296,722,680],{"class":302},[296,724,725],{"class":683},"persist",[296,727,687],{"class":302},[296,729,730],{"class":319},"user",[296,732,705],{"class":302},[282,734,735],{},"로 새로운 엔티티를 영속 상태로 만들거나,",[286,737,739],{"className":288,"code":738,"language":290,"meta":291,"style":291},"entityManager.remove(user);\n",[293,740,741],{"__ignoreMap":291},[296,742,743,745,747,750,752,754],{"class":298,"line":299},[296,744,677],{"class":319},[296,746,680],{"class":302},[296,748,749],{"class":683},"remove",[296,751,687],{"class":302},[296,753,730],{"class":319},[296,755,705],{"class":302},[282,757,758],{},"로 삭제할 수도 있다.",[282,760,761],{},"즉 EntityManager는:",[286,763,766],{"className":764,"code":765,"language":365,"meta":291},[363],"Entity 조회\nEntity 저장\nEntity 삭제\nEntity 상태 관리\n영속성 컨텍스트 접근\nFlush\n",[293,767,765],{"__ignoreMap":291},[282,769,770],{},"등 JPA의 엔티티 관리와 관련된 여러 기능을 담당한다.",[443,772],{},[277,774,776],{"id":775},"_3-persistencecontext와-entitymanager의-관계","🔗 3. @PersistenceContext와 EntityManager의 관계",[282,778,779],{},"둘의 관계를 간단하게 표현하면 다음과 같다.",[286,781,784],{"className":782,"code":783,"language":365,"meta":291},[363],"@PersistenceContext\n\n        ↓\n\nEntityManager 주입\n\n        ↓\n\nPersistence Context 관리\n\n        ↓\n\nEntity 상태 관리\n",[293,785,783],{"__ignoreMap":291},[282,787,788],{},"따라서:",[286,790,791],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,792,793,799],{"__ignoreMap":291},[296,794,795,797],{"class":298,"line":299},[296,796,303],{"class":302},[296,798,307],{"class":306},[296,800,801,803,805,807],{"class":298,"line":310},[296,802,313],{"class":306},[296,804,316],{"class":306},[296,806,320],{"class":319},[296,808,323],{"class":302},[282,810,811],{},"라는 코드는 단순히 \"EntityManager 객체 하나를 생성해서 넣어주세요\"라는 의미로만 이해하면 부족하다.",[282,813,814,815,818],{},"JPA가 관리하는 EntityManager를 통해 ",[347,816,817],{},"영속성 컨텍스트와 상호작용하기 위한 진입점","을 제공받는 것이다.",[443,820],{},[277,822,824],{"id":823},"_4-영속성-컨텍스트란-무엇인가","🌱 4. 영속성 컨텍스트란 무엇인가?",[282,826,827,829],{},[293,828,344],{},"를 이해하기 위해 가장 중요한 개념이 바로 **영속성 컨텍스트(Persistence Context)**다.",[282,831,832],{},"영속성 컨텍스트는 쉽게 표현하면:",[328,834,835],{},[282,836,837],{},[347,838,839],{},"JPA가 엔티티를 관리하기 위해 사용하는 논리적인 저장 공간",[282,841,842],{},"이라고 볼 수 있다.",[282,844,845],{},"예를 들어:",[286,847,849],{"className":288,"code":848,"language":290,"meta":291,"style":291},"User user = entityManager.find(User.class, 1L);\n",[293,850,851],{"__ignoreMap":291},[296,852,853,855,858,861,863,865,867,869,871,873,875,877,879],{"class":298,"line":299},[296,854,690],{"class":306},[296,856,857],{"class":319}," user ",[296,859,860],{"class":302},"=",[296,862,320],{"class":319},[296,864,680],{"class":302},[296,866,684],{"class":683},[296,868,687],{"class":302},[296,870,690],{"class":319},[296,872,680],{"class":302},[296,874,695],{"class":319},[296,876,698],{"class":302},[296,878,702],{"class":701},[296,880,705],{"class":302},[282,882,883],{},"을 실행했다고 하자.",[282,885,886],{},"단순히:",[286,888,891],{"className":889,"code":890,"language":365,"meta":291},[363],"SELECT SQL 실행\n        ↓\nJava 객체 생성\n        ↓\n반환\n",[293,892,890],{"__ignoreMap":291},[282,894,895],{},"으로 끝나는 것이 아니다.",[282,897,898,899,901],{},"조회된 ",[293,900,690],{}," 엔티티는 영속성 컨텍스트에 등록되어 JPA가 관리하게 된다.",[286,903,906],{"className":904,"code":905,"language":365,"meta":291},[363],"Database\n\n   ↓\n\nEntityManager\n\n   ↓\n\nPersistence Context\n\n   ↓\n\nUser Entity\n",[293,907,905],{"__ignoreMap":291},[282,909,910],{},"이후 해당 엔티티가 변경되었는지 JPA가 추적할 수 있게 된다.",[443,912],{},[277,914,916],{"id":915},"_5-영속성-컨텍스트가-필요한-이유","🧠 5. 영속성 컨텍스트가 필요한 이유",[282,918,919],{},"그렇다면 JPA는 왜 굳이 엔티티를 영속성 컨텍스트에 관리할까?",[282,921,922],{},"가장 대표적인 이유는 다음과 같다.",[286,924,927],{"className":925,"code":926,"language":365,"meta":291},[363],"1차 캐시\n\n동일성 보장\n\nDirty Checking\n\n쓰기 지연\n\nFlush 관리\n",[293,928,926],{"__ignoreMap":291},[282,930,931,932,935],{},"즉 영속성 컨텍스트는 단순한 캐시가 아니라 ",[347,933,934],{},"JPA가 엔티티의 상태를 관리하기 위한 핵심 공간","이다.",[443,937],{},[277,939,941],{"id":940},"_6-1차-캐시","📦 6. 1차 캐시",[282,943,944,945,947],{},"영속성 컨텍스트에는 ",[347,946,404],{},"가 존재한다.",[282,949,845],{},[286,951,953],{"className":288,"code":952,"language":290,"meta":291,"style":291},"User user1 = entityManager.find(User.class, 1L);\nUser user2 = entityManager.find(User.class, 1L);\n",[293,954,955,984],{"__ignoreMap":291},[296,956,957,959,962,964,966,968,970,972,974,976,978,980,982],{"class":298,"line":299},[296,958,690],{"class":306},[296,960,961],{"class":319}," user1 ",[296,963,860],{"class":302},[296,965,320],{"class":319},[296,967,680],{"class":302},[296,969,684],{"class":683},[296,971,687],{"class":302},[296,973,690],{"class":319},[296,975,680],{"class":302},[296,977,695],{"class":319},[296,979,698],{"class":302},[296,981,702],{"class":701},[296,983,705],{"class":302},[296,985,986,988,991,993,995,997,999,1001,1003,1005,1007,1009,1011],{"class":298,"line":310},[296,987,690],{"class":306},[296,989,990],{"class":319}," user2 ",[296,992,860],{"class":302},[296,994,320],{"class":319},[296,996,680],{"class":302},[296,998,684],{"class":683},[296,1000,687],{"class":302},[296,1002,690],{"class":319},[296,1004,680],{"class":302},[296,1006,695],{"class":319},[296,1008,698],{"class":302},[296,1010,702],{"class":701},[296,1012,705],{"class":302},[282,1014,883],{},[282,1016,1017,1018,1020],{},"두 번째 ",[293,1019,425],{},"에서는 항상 데이터베이스에 다시 접근하는 것은 아니다.",[282,1022,1023],{},"처음 조회한 엔티티가 영속성 컨텍스트에 있다면 해당 엔티티를 다시 사용할 수 있다.",[282,1025,1026],{},"흐름은:",[286,1028,1031],{"className":1029,"code":1030,"language":365,"meta":291},[363],"첫 번째 find()\n\nDatabase 조회\n\n      ↓\n\nUser Entity 생성\n\n      ↓\n\nPersistence Context 등록\n\n      ↓\n\nuser1 반환\n",[293,1032,1030],{"__ignoreMap":291},[282,1034,1035],{},"그리고:",[286,1037,1040],{"className":1038,"code":1039,"language":365,"meta":291},[363],"두 번째 find()\n\n      ↓\n\nPersistence Context 확인\n\n      ↓\n\n이미 존재\n\n      ↓\n\n기존 Entity 반환\n",[293,1041,1039],{"__ignoreMap":291},[282,1043,1044],{},"이 된다.",[443,1046],{},[277,1048,1050],{"id":1049},"_7-동일성-보장","🔎 7. 동일성 보장",[282,1052,1053,1054,935],{},"1차 캐시와 연결되는 중요한 특징이 ",[347,1055,407],{},[282,1057,1058],{},"앞서 작성한 코드:",[286,1060,1061],{"className":288,"code":952,"language":290,"meta":291,"style":291},[293,1062,1063,1091],{"__ignoreMap":291},[296,1064,1065,1067,1069,1071,1073,1075,1077,1079,1081,1083,1085,1087,1089],{"class":298,"line":299},[296,1066,690],{"class":306},[296,1068,961],{"class":319},[296,1070,860],{"class":302},[296,1072,320],{"class":319},[296,1074,680],{"class":302},[296,1076,684],{"class":683},[296,1078,687],{"class":302},[296,1080,690],{"class":319},[296,1082,680],{"class":302},[296,1084,695],{"class":319},[296,1086,698],{"class":302},[296,1088,702],{"class":701},[296,1090,705],{"class":302},[296,1092,1093,1095,1097,1099,1101,1103,1105,1107,1109,1111,1113,1115,1117],{"class":298,"line":310},[296,1094,690],{"class":306},[296,1096,990],{"class":319},[296,1098,860],{"class":302},[296,1100,320],{"class":319},[296,1102,680],{"class":302},[296,1104,684],{"class":683},[296,1106,687],{"class":302},[296,1108,690],{"class":319},[296,1110,680],{"class":302},[296,1112,695],{"class":319},[296,1114,698],{"class":302},[296,1116,702],{"class":701},[296,1118,705],{"class":302},[282,1120,1121],{},"에서 같은 영속성 컨텍스트 안이라면:",[286,1123,1125],{"className":288,"code":1124,"language":290,"meta":291,"style":291},"user1 == user2\n",[293,1126,1127],{"__ignoreMap":291},[296,1128,1129,1132,1135],{"class":298,"line":299},[296,1130,1131],{"class":319},"user1 ",[296,1133,1134],{"class":302},"==",[296,1136,1137],{"class":319}," user2\n",[282,1139,1140,1141,1143],{},"가 ",[293,1142,275],{},"가 된다.",[282,1145,1146],{},"즉 같은 데이터베이스 Row를 나타내는 엔티티라면 같은 영속성 컨텍스트 안에서 동일한 엔티티 인스턴스를 반환한다.",[282,1148,1149],{},"이것이 JPA의:",[328,1151,1152],{},[282,1153,1154],{},[347,1155,1156],{},"Repeatable Read 수준의 동일성 보장",[282,1158,1159],{},"을 이해하는 중요한 부분이다.",[282,1161,1162],{},"단순히 SQL 결과를 매번 새로운 객체로 만드는 것과는 다른 방식으로 엔티티를 관리하는 것이다.",[443,1164],{},[277,1166,1168],{"id":1167},"_8-엔티티의-생명주기","🧩 8. 엔티티의 생명주기",[282,1170,1171],{},"JPA에서는 엔티티의 상태를 이해하는 것이 중요하다.",[282,1173,1174],{},"대표적인 상태는 다음과 같다.",[286,1176,1179],{"className":1177,"code":1178,"language":365,"meta":291},[363],"비영속 (Transient)\n\n영속 (Persistent)\n\n준영속 (Detached)\n\n삭제 (Removed)\n",[293,1180,1178],{"__ignoreMap":291},[282,1182,1183],{},"각 상태가 어떤 의미인지 알아보자.",[443,1185],{},[277,1187,1189],{"id":1188},"_9-비영속-상태","🌱 9. 비영속 상태",[282,1191,1192],{},"비영속 상태는 아직 JPA가 관리하지 않는 일반 Java 객체다.",[286,1194,1196],{"className":288,"code":1195,"language":290,"meta":291,"style":291},"User user = new User(\"콩이\");\n",[293,1197,1198],{"__ignoreMap":291},[296,1199,1200,1202,1204,1206,1210,1212,1214,1217,1221,1223],{"class":298,"line":299},[296,1201,690],{"class":306},[296,1203,857],{"class":319},[296,1205,860],{"class":302},[296,1207,1209],{"class":1208},"s7zQu"," new",[296,1211,605],{"class":683},[296,1213,687],{"class":302},[296,1215,1216],{"class":302},"\"",[296,1218,1220],{"class":1219},"sfazB","콩이",[296,1222,1216],{"class":302},[296,1224,705],{"class":302},[282,1226,1227,1228,1230],{},"현재 ",[293,1229,730],{},"는 단순한 Java 객체다.",[282,1232,1233],{},"아직:",[286,1235,1238],{"className":1236,"code":1237,"language":365,"meta":291},[363],"Persistence Context\n        │\n        X\n        │\n      User\n",[293,1239,1237],{"__ignoreMap":291},[282,1241,1242],{},"상태다.",[282,1244,1245],{},"JPA는 이 객체를 관리하지 않는다.",[443,1247],{},[277,1249,1251],{"id":1250},"_10-영속-상태","📥 10. 영속 상태",[282,1253,1254],{},"EntityManager를 통해 엔티티를 영속성 컨텍스트에 등록하면 영속 상태가 된다.",[286,1256,1258],{"className":288,"code":1257,"language":290,"meta":291,"style":291},"User user = new User(\"콩이\");\n\nentityManager.persist(user);\n",[293,1259,1260,1282,1286],{"__ignoreMap":291},[296,1261,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280],{"class":298,"line":299},[296,1263,690],{"class":306},[296,1265,857],{"class":319},[296,1267,860],{"class":302},[296,1269,1209],{"class":1208},[296,1271,605],{"class":683},[296,1273,687],{"class":302},[296,1275,1216],{"class":302},[296,1277,1220],{"class":1219},[296,1279,1216],{"class":302},[296,1281,705],{"class":302},[296,1283,1284],{"class":298,"line":310},[296,1285,493],{"emptyLinePlaceholder":492},[296,1287,1288,1290,1292,1294,1296,1298],{"class":298,"line":489},[296,1289,677],{"class":319},[296,1291,680],{"class":302},[296,1293,725],{"class":683},[296,1295,687],{"class":302},[296,1297,730],{"class":319},[296,1299,705],{"class":302},[282,1301,1302],{},"이후:",[286,1304,1307],{"className":1305,"code":1306,"language":365,"meta":291},[363],"User\n\n ↓ persist()\n\nPersistence Context\n",[293,1308,1306],{"__ignoreMap":291},[282,1310,1311],{},"관계가 된다.",[282,1313,1314],{},"이제 JPA가 해당 엔티티를 관리하기 시작한다.",[282,1316,1317],{},"따라서 이후 엔티티의 변경사항을 JPA가 추적할 수 있다.",[443,1319],{},[277,1321,1323],{"id":1322},"_11-조회한-엔티티도-영속-상태가-된다","🔎 11. 조회한 엔티티도 영속 상태가 된다",[282,1325,1326],{},"조회 역시 마찬가지다.",[286,1328,1329],{"className":288,"code":848,"language":290,"meta":291,"style":291},[293,1330,1331],{"__ignoreMap":291},[296,1332,1333,1335,1337,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357],{"class":298,"line":299},[296,1334,690],{"class":306},[296,1336,857],{"class":319},[296,1338,860],{"class":302},[296,1340,320],{"class":319},[296,1342,680],{"class":302},[296,1344,684],{"class":683},[296,1346,687],{"class":302},[296,1348,690],{"class":319},[296,1350,680],{"class":302},[296,1352,695],{"class":319},[296,1354,698],{"class":302},[296,1356,702],{"class":701},[296,1358,705],{"class":302},[282,1360,1361],{},"이렇게 조회된 엔티티는 영속성 컨텍스트에서 관리된다.",[282,1363,553],{},[286,1365,1368],{"className":1366,"code":1367,"language":365,"meta":291},[363],"find()\n\n↓\n\nDatabase 조회\n\n↓\n\nEntity 생성\n\n↓\n\nPersistence Context 등록\n\n↓\n\nPersistent 상태\n",[293,1369,1367],{"__ignoreMap":291},[282,1371,1143],{},[443,1373],{},[277,1375,1377],{"id":1376},"_12-준영속-상태","🔄 12. 준영속 상태",[282,1379,1380],{},"영속성 컨텍스트에서 관리되던 엔티티가 더 이상 관리되지 않는 상태를 **준영속(Detached)**이라고 한다.",[282,1382,1383],{},"예:",[286,1385,1387],{"className":288,"code":1386,"language":290,"meta":291,"style":291},"entityManager.detach(user);\n",[293,1388,1389],{"__ignoreMap":291},[296,1390,1391,1393,1395,1398,1400,1402],{"class":298,"line":299},[296,1392,677],{"class":319},[296,1394,680],{"class":302},[296,1396,1397],{"class":683},"detach",[296,1399,687],{"class":302},[296,1401,730],{"class":319},[296,1403,705],{"class":302},[282,1405,1406],{},"또는:",[286,1408,1410],{"className":288,"code":1409,"language":290,"meta":291,"style":291},"entityManager.clear();\n",[293,1411,1412],{"__ignoreMap":291},[296,1413,1414,1416,1418,1421],{"class":298,"line":299},[296,1415,677],{"class":319},[296,1417,680],{"class":302},[296,1419,1420],{"class":683},"clear",[296,1422,1423],{"class":302},"();\n",[282,1425,1426],{},"를 사용하면 영속성 컨텍스트에서 엔티티가 분리될 수 있다.",[282,1428,1429],{},"이 상태에서는:",[286,1431,1434],{"className":1432,"code":1433,"language":365,"meta":291},[363],"Entity\n\n   X\n\nPersistence Context\n",[293,1435,1433],{"__ignoreMap":291},[282,1437,1143],{},[282,1439,1440],{},"따라서 더 이상 해당 엔티티의 변경사항을 JPA가 자동으로 추적하지 않는다.",[443,1442],{},[277,1444,1446],{"id":1445},"️-13-삭제-상태","🗑️ 13. 삭제 상태",[282,1448,1449],{},"엔티티를 삭제하려면:",[286,1451,1452],{"className":288,"code":738,"language":290,"meta":291,"style":291},[293,1453,1454],{"__ignoreMap":291},[296,1455,1456,1458,1460,1462,1464,1466],{"class":298,"line":299},[296,1457,677],{"class":319},[296,1459,680],{"class":302},[296,1461,749],{"class":683},[296,1463,687],{"class":302},[296,1465,730],{"class":319},[296,1467,705],{"class":302},[282,1469,1470],{},"를 호출한다.",[282,1472,1473],{},"그러면 해당 엔티티는 삭제 대상으로 관리된다.",[282,1475,1476],{},"트랜잭션이 Flush되는 과정에서 실제 DELETE SQL이 실행된다.",[286,1478,1481],{"className":1479,"code":1480,"language":365,"meta":291},[363],"remove()\n\n↓\n\n삭제 대상으로 등록\n\n↓\n\nFlush\n\n↓\n\nDELETE SQL\n\n↓\n\nDatabase 반영\n",[293,1482,1480],{"__ignoreMap":291},[443,1484],{},[277,1486,1488],{"id":1487},"_14-entitymanager의-주요-메서드","🔎 14. EntityManager의 주요 메서드",[282,1490,1491],{},"EntityManager를 직접 사용할 때 자주 등장하는 메서드는 다음과 같다.",[1493,1494,1495,1508],"table",{},[1496,1497,1498],"thead",{},[1499,1500,1501,1505],"tr",{},[1502,1503,1504],"th",{},"메서드",[1502,1506,1507],{},"역할",[1509,1510,1511,1521,1530,1539,1549,1559,1569],"tbody",{},[1499,1512,1513,1518],{},[1514,1515,1516],"td",{},[293,1517,421],{},[1514,1519,1520],{},"새로운 엔티티를 영속 상태로 등록",[1499,1522,1523,1527],{},[1514,1524,1525],{},[293,1526,425],{},[1514,1528,1529],{},"엔티티 조회",[1499,1531,1532,1536],{},[1514,1533,1534],{},[293,1535,428],{},[1514,1537,1538],{},"엔티티 삭제",[1499,1540,1541,1546],{},[1514,1542,1543],{},[293,1544,1545],{},"detach()",[1514,1547,1548],{},"엔티티를 영속성 컨텍스트에서 분리",[1499,1550,1551,1556],{},[1514,1552,1553],{},[293,1554,1555],{},"clear()",[1514,1557,1558],{},"영속성 컨텍스트 전체 초기화",[1499,1560,1561,1566],{},[1514,1562,1563],{},[293,1564,1565],{},"flush()",[1514,1567,1568],{},"변경 내용을 DB에 반영",[1499,1570,1571,1575],{},[1514,1572,1573],{},[293,1574,431],{},[1514,1576,1577],{},"준영속 엔티티를 병합",[282,1579,1580],{},"각각의 동작은 영속성 컨텍스트와 밀접하게 연결되어 있다.",[443,1582],{},[277,1584,1586],{"id":1585},"️-15-persist는-바로-insert를-실행할까","🛠️ 15. persist()는 바로 INSERT를 실행할까?",[282,1588,1589],{},"다음 코드를 보자.",[286,1591,1592],{"className":288,"code":1257,"language":290,"meta":291,"style":291},[293,1593,1594,1616,1620],{"__ignoreMap":291},[296,1595,1596,1598,1600,1602,1604,1606,1608,1610,1612,1614],{"class":298,"line":299},[296,1597,690],{"class":306},[296,1599,857],{"class":319},[296,1601,860],{"class":302},[296,1603,1209],{"class":1208},[296,1605,605],{"class":683},[296,1607,687],{"class":302},[296,1609,1216],{"class":302},[296,1611,1220],{"class":1219},[296,1613,1216],{"class":302},[296,1615,705],{"class":302},[296,1617,1618],{"class":298,"line":310},[296,1619,493],{"emptyLinePlaceholder":492},[296,1621,1622,1624,1626,1628,1630,1632],{"class":298,"line":489},[296,1623,677],{"class":319},[296,1625,680],{"class":302},[296,1627,725],{"class":683},[296,1629,687],{"class":302},[296,1631,730],{"class":319},[296,1633,705],{"class":302},[282,1635,1636],{},"여기서 흔히 하는 오해가 있다.",[286,1638,1641],{"className":1639,"code":1640,"language":365,"meta":291},[363],"persist()\n\n↓\n\n즉시 INSERT SQL\n",[293,1642,1640],{"__ignoreMap":291},[282,1644,1645],{},"이라고 생각하는 것이다.",[282,1647,1648,1649,1651,1652,935],{},"하지만 ",[293,1650,421],{},"의 핵심은 ",[347,1653,1654],{},"엔티티를 영속성 컨텍스트에 등록하는 것",[282,1656,1657],{},"실제 SQL 실행 시점은 Flush 정책과 트랜잭션 상황 등에 따라 달라질 수 있다.",[282,1659,553],{},[286,1661,1664],{"className":1662,"code":1663,"language":365,"meta":291},[363],"persist()\n\n↓\n\nPersistence Context 등록\n\n↓\n\nFlush\n\n↓\n\nINSERT SQL\n",[293,1665,1663],{"__ignoreMap":291},[282,1667,1668],{},"흐름으로 이해하는 것이 좋다.",[443,1670],{},[277,1672,1674],{"id":1673},"_16-dirty-checking이란","🧠 16. Dirty Checking이란?",[282,1676,1677,1678,935],{},"JPA의 대표적인 기능 중 하나가 ",[347,1679,410],{},[282,1681,1682],{},"말 그대로:",[328,1684,1685],{},[282,1686,1687],{},"\"관리 중인 엔티티의 상태가 변경되었는지 확인한다.\"",[282,1689,1690],{},"는 개념이다.",[282,1692,845],{},[286,1694,1696],{"className":288,"code":1695,"language":290,"meta":291,"style":291},"@Transactional\npublic void changeName(Long userId) {\n\n    User user = entityManager.find(User.class, userId);\n\n    user.changeName(\"두부\");\n}\n",[293,1697,1698,1705,1728,1732,1761,1765,1786],{"__ignoreMap":291},[296,1699,1700,1702],{"class":298,"line":299},[296,1701,303],{"class":302},[296,1703,1704],{"class":306},"Transactional\n",[296,1706,1707,1709,1712,1715,1717,1720,1723,1726],{"class":298,"line":310},[296,1708,476],{"class":306},[296,1710,1711],{"class":306}," void",[296,1713,1714],{"class":683}," changeName",[296,1716,687],{"class":302},[296,1718,1719],{"class":306},"Long",[296,1721,1722],{"class":319}," userId",[296,1724,1725],{"class":302},")",[296,1727,486],{"class":302},[296,1729,1730],{"class":298,"line":489},[296,1731,493],{"emptyLinePlaceholder":492},[296,1733,1734,1737,1739,1741,1743,1745,1747,1749,1751,1753,1755,1757,1759],{"class":298,"line":496},[296,1735,1736],{"class":306},"    User",[296,1738,857],{"class":319},[296,1740,860],{"class":302},[296,1742,320],{"class":319},[296,1744,680],{"class":302},[296,1746,684],{"class":683},[296,1748,687],{"class":302},[296,1750,690],{"class":319},[296,1752,680],{"class":302},[296,1754,695],{"class":319},[296,1756,698],{"class":302},[296,1758,1722],{"class":319},[296,1760,705],{"class":302},[296,1762,1763],{"class":298,"line":504},[296,1764,493],{"emptyLinePlaceholder":492},[296,1766,1767,1770,1772,1775,1777,1779,1782,1784],{"class":298,"line":516},[296,1768,1769],{"class":319},"    user",[296,1771,680],{"class":302},[296,1773,1774],{"class":683},"changeName",[296,1776,687],{"class":302},[296,1778,1216],{"class":302},[296,1780,1781],{"class":1219},"두부",[296,1783,1216],{"class":302},[296,1785,705],{"class":302},[296,1787,1788],{"class":298,"line":521},[296,1789,524],{"class":302},[282,1791,1792],{},"여기에는 다음 코드가 없다.",[286,1794,1796],{"className":288,"code":1795,"language":290,"meta":291,"style":291},"entityManager.save(user);\n",[293,1797,1798],{"__ignoreMap":291},[296,1799,1800,1802,1804,1807,1809,1811],{"class":298,"line":299},[296,1801,677],{"class":319},[296,1803,680],{"class":302},[296,1805,1806],{"class":683},"save",[296,1808,687],{"class":302},[296,1810,730],{"class":319},[296,1812,705],{"class":302},[282,1814,1406],{},[286,1816,1818],{"className":288,"code":1817,"language":290,"meta":291,"style":291},"entityManager.update(user);\n",[293,1819,1820],{"__ignoreMap":291},[296,1821,1822,1824,1826,1829,1831,1833],{"class":298,"line":299},[296,1823,677],{"class":319},[296,1825,680],{"class":302},[296,1827,1828],{"class":683},"update",[296,1830,687],{"class":302},[296,1832,730],{"class":319},[296,1834,705],{"class":302},[282,1836,1837],{},"그런데도 데이터베이스가 변경될 수 있다.",[282,1839,1840],{},"이것이 Dirty Checking 때문이다.",[443,1842],{},[277,1844,1846],{"id":1845},"_17-dirty-checking은-어떻게-동작할까","🔎 17. Dirty Checking은 어떻게 동작할까?",[282,1848,1849],{},"JPA는 엔티티가 영속성 컨텍스트에 들어올 때 엔티티의 상태를 관리한다.",[282,1851,1852],{},"개념적으로 보면:",[286,1854,1857],{"className":1855,"code":1856,"language":365,"meta":291},[363],"조회 당시 상태\n\nname = \"콩이\"\n\n        ↓\n\nEntity 변경\n\nname = \"두부\"\n\n        ↓\n\nFlush 시점\n\n조회 당시 상태와 비교\n\n        ↓\n\n변경 감지\n\n        ↓\n\nUPDATE SQL\n",[293,1858,1856],{"__ignoreMap":291},[282,1860,1861],{},"이렇게 동작한다.",[282,1863,788],{},[286,1865,1867],{"className":288,"code":1866,"language":290,"meta":291,"style":291},"user.changeName(\"두부\");\n",[293,1868,1869],{"__ignoreMap":291},[296,1870,1871,1873,1875,1877,1879,1881,1883,1885],{"class":298,"line":299},[296,1872,730],{"class":319},[296,1874,680],{"class":302},[296,1876,1774],{"class":683},[296,1878,687],{"class":302},[296,1880,1216],{"class":302},[296,1882,1781],{"class":1219},[296,1884,1216],{"class":302},[296,1886,705],{"class":302},[282,1888,1889],{},"처럼 엔티티의 상태만 변경해도 트랜잭션 종료 과정에서 변경사항이 데이터베이스에 반영될 수 있다.",[443,1891],{},[277,1893,1895],{"id":1894},"_18-dirty-checking에서-중요한-점","🔥 18. Dirty Checking에서 중요한 점",[282,1897,1898,1899,1902],{},"Dirty Checking은 ",[347,1900,1901],{},"영속 상태의 엔티티","를 대상으로 한다.",[282,1904,1383],{},[286,1906,1908],{"className":288,"code":1907,"language":290,"meta":291,"style":291},"User user = entityManager.find(User.class, 1L);\n\nuser.changeName(\"두부\");\n",[293,1909,1910,1938,1942],{"__ignoreMap":291},[296,1911,1912,1914,1916,1918,1920,1922,1924,1926,1928,1930,1932,1934,1936],{"class":298,"line":299},[296,1913,690],{"class":306},[296,1915,857],{"class":319},[296,1917,860],{"class":302},[296,1919,320],{"class":319},[296,1921,680],{"class":302},[296,1923,684],{"class":683},[296,1925,687],{"class":302},[296,1927,690],{"class":319},[296,1929,680],{"class":302},[296,1931,695],{"class":319},[296,1933,698],{"class":302},[296,1935,702],{"class":701},[296,1937,705],{"class":302},[296,1939,1940],{"class":298,"line":310},[296,1941,493],{"emptyLinePlaceholder":492},[296,1943,1944,1946,1948,1950,1952,1954,1956,1958],{"class":298,"line":489},[296,1945,730],{"class":319},[296,1947,680],{"class":302},[296,1949,1774],{"class":683},[296,1951,687],{"class":302},[296,1953,1216],{"class":302},[296,1955,1781],{"class":1219},[296,1957,1216],{"class":302},[296,1959,705],{"class":302},[282,1961,1962,1963,1965],{},"이 경우 ",[293,1964,730],{},"는 영속 상태이므로 변경을 추적할 수 있다.",[282,1967,1968],{},"반면:",[286,1970,1972],{"className":288,"code":1971,"language":290,"meta":291,"style":291},"User user = ...;\n\nentityManager.detach(user);\n\nuser.changeName(\"두부\");\n",[293,1973,1974,1985,1989,2003,2007],{"__ignoreMap":291},[296,1975,1976,1978,1980,1982],{"class":298,"line":299},[296,1977,690],{"class":306},[296,1979,857],{"class":319},[296,1981,860],{"class":302},[296,1983,1984],{"class":302}," ...;\n",[296,1986,1987],{"class":298,"line":310},[296,1988,493],{"emptyLinePlaceholder":492},[296,1990,1991,1993,1995,1997,1999,2001],{"class":298,"line":489},[296,1992,677],{"class":319},[296,1994,680],{"class":302},[296,1996,1397],{"class":683},[296,1998,687],{"class":302},[296,2000,730],{"class":319},[296,2002,705],{"class":302},[296,2004,2005],{"class":298,"line":496},[296,2006,493],{"emptyLinePlaceholder":492},[296,2008,2009,2011,2013,2015,2017,2019,2021,2023],{"class":298,"line":504},[296,2010,730],{"class":319},[296,2012,680],{"class":302},[296,2014,1774],{"class":683},[296,2016,687],{"class":302},[296,2018,1216],{"class":302},[296,2020,1781],{"class":1219},[296,2022,1216],{"class":302},[296,2024,705],{"class":302},[282,2026,2027],{},"처럼 준영속 상태가 되면 해당 변경사항은 일반적인 Dirty Checking 대상이 아니다.",[282,2029,788],{},[286,2031,2034],{"className":2032,"code":2033,"language":365,"meta":291},[363],"영속성 컨텍스트\n\n+\n\n영속 상태 Entity\n\n+\n\nTransaction\n\n↓\n\nDirty Checking\n",[293,2035,2033],{"__ignoreMap":291},[282,2037,2038],{},"의 관계를 함께 이해하는 것이 중요하다.",[443,2040],{},[277,2042,2044],{"id":2043},"_19-flush란-무엇인가","🚽 19. Flush란 무엇인가?",[282,2046,2047,2048,2050],{},"JPA를 이해하다 보면 ",[293,2049,1565],{},"라는 개념이 자주 등장한다.",[282,2052,2053],{},"Flush는 쉽게 말하면:",[328,2055,2056],{},[282,2057,2058],{},[347,2059,2060],{},"영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 과정",[282,2062,935],{},[282,2064,845],{},[286,2066,2067],{"className":288,"code":1866,"language":290,"meta":291,"style":291},[293,2068,2069],{"__ignoreMap":291},[296,2070,2071,2073,2075,2077,2079,2081,2083,2085],{"class":298,"line":299},[296,2072,730],{"class":319},[296,2074,680],{"class":302},[296,2076,1774],{"class":683},[296,2078,687],{"class":302},[296,2080,1216],{"class":302},[296,2082,1781],{"class":1219},[296,2084,1216],{"class":302},[296,2086,705],{"class":302},[282,2088,2089],{},"를 실행했다고 하자.",[282,2091,2092],{},"이 순간 바로 DB에 UPDATE가 실행된다고 생각하기보다는:",[286,2094,2097],{"className":2095,"code":2096,"language":365,"meta":291},[363],"Java Entity 변경\n\n↓\n\nPersistence Context 변경\n\n↓\n\nFlush\n\n↓\n\nUPDATE SQL\n\n↓\n\nDatabase\n",[293,2098,2096],{"__ignoreMap":291},[282,2100,1668],{},[443,2102],{},[277,2104,2106],{"id":2105},"_20-flush와-commit은-같은-것일까","🔎 20. Flush와 Commit은 같은 것일까?",[282,2108,2109],{},"아니다.",[282,2111,2112],{},"이 둘은 자주 혼동하지만 서로 다른 개념이다.",[286,2114,2117],{"className":2115,"code":2116,"language":365,"meta":291},[363],"Flush\n\n→ 변경 내용을 DB에 동기화\n\nCommit\n\n→ Transaction을 최종 확정\n",[293,2118,2116],{"__ignoreMap":291},[282,2120,2121],{},"즉 Flush가 발생했다고 해서 Transaction이 최종적으로 성공한 것은 아니다.",[282,2123,2124],{},"개념적으로:",[286,2126,2129],{"className":2127,"code":2128,"language":365,"meta":291},[363],"Entity 변경\n\n↓\n\nFlush\n\n↓\n\nSQL 실행\n\n↓\n\nTransaction Commit\n\n↓\n\n최종 반영\n",[293,2130,2128],{"__ignoreMap":291},[282,2132,2133],{},"과 같은 흐름으로 이해할 수 있다.",[282,2135,2136],{},"만약 Flush 이후 Transaction이 Rollback된다면 해당 변경사항은 최종적으로 반영되지 않는다.",[443,2138],{},[277,2140,2142],{"id":2141},"️-21-flush는-언제-발생할까","⚙️ 21. Flush는 언제 발생할까?",[282,2144,2145],{},"Flush는 여러 상황에서 발생할 수 있다.",[282,2147,2148],{},"대표적으로:",[286,2150,2153],{"className":2151,"code":2152,"language":365,"meta":291},[363],"Transaction Commit\n\nJPQL \u002F Query 실행 전\n\nentityManager.flush() 직접 호출\n",[293,2154,2152],{"__ignoreMap":291},[282,2156,2157],{},"등이 있다.",[282,2159,2160],{},"특히 JPQL을 실행하기 전에 영속성 컨텍스트의 변경 내용을 DB와 맞춰야 하는 상황에서는 Flush가 발생할 수 있다.",[282,2162,845],{},[286,2164,2166],{"className":288,"code":2165,"language":290,"meta":291,"style":291},"User user = entityManager.find(User.class, 1L);\n\nuser.changeName(\"두부\");\n\nList\u003CUser> users = entityManager\n    .createQuery(\n        \"select u from User u\",\n        User.class\n    )\n    .getResultList();\n",[293,2167,2168,2196,2200,2218,2222,2243,2254,2267,2277,2282],{"__ignoreMap":291},[296,2169,2170,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190,2192,2194],{"class":298,"line":299},[296,2171,690],{"class":306},[296,2173,857],{"class":319},[296,2175,860],{"class":302},[296,2177,320],{"class":319},[296,2179,680],{"class":302},[296,2181,684],{"class":683},[296,2183,687],{"class":302},[296,2185,690],{"class":319},[296,2187,680],{"class":302},[296,2189,695],{"class":319},[296,2191,698],{"class":302},[296,2193,702],{"class":701},[296,2195,705],{"class":302},[296,2197,2198],{"class":298,"line":310},[296,2199,493],{"emptyLinePlaceholder":492},[296,2201,2202,2204,2206,2208,2210,2212,2214,2216],{"class":298,"line":489},[296,2203,730],{"class":319},[296,2205,680],{"class":302},[296,2207,1774],{"class":683},[296,2209,687],{"class":302},[296,2211,1216],{"class":302},[296,2213,1781],{"class":1219},[296,2215,1216],{"class":302},[296,2217,705],{"class":302},[296,2219,2220],{"class":298,"line":496},[296,2221,493],{"emptyLinePlaceholder":492},[296,2223,2224,2227,2230,2232,2235,2238,2240],{"class":298,"line":504},[296,2225,2226],{"class":306},"List",[296,2228,2229],{"class":302},"\u003C",[296,2231,690],{"class":306},[296,2233,2234],{"class":302},">",[296,2236,2237],{"class":319}," users ",[296,2239,860],{"class":302},[296,2241,2242],{"class":319}," entityManager\n",[296,2244,2245,2248,2251],{"class":298,"line":516},[296,2246,2247],{"class":302},"    .",[296,2249,2250],{"class":683},"createQuery",[296,2252,2253],{"class":302},"(\n",[296,2255,2256,2259,2262,2264],{"class":298,"line":521},[296,2257,2258],{"class":302},"        \"",[296,2260,2261],{"class":1219},"select u from User u",[296,2263,1216],{"class":302},[296,2265,2266],{"class":302},",\n",[296,2268,2269,2272,2274],{"class":298,"line":644},[296,2270,2271],{"class":319},"        User",[296,2273,680],{"class":302},[296,2275,2276],{"class":319},"class\n",[296,2278,2279],{"class":298,"line":657},[296,2280,2281],{"class":302},"    )\n",[296,2283,2284,2286,2289],{"class":298,"line":662},[296,2285,2247],{"class":302},[296,2287,2288],{"class":683},"getResultList",[296,2290,1423],{"class":302},[282,2292,2293],{},"이런 상황에서는 변경된 엔티티 상태와 쿼리 결과의 일관성을 맞추기 위해 Flush가 고려된다.",[443,2295],{},[277,2297,2299],{"id":2298},"_22-transaction과-영속성-컨텍스트","🧠 22. Transaction과 영속성 컨텍스트",[282,2301,2302],{},"JPA를 이해할 때 Transaction도 함께 봐야 한다.",[282,2304,2305],{},"일반적인 Spring Data JPA 환경에서는 다음과 같은 코드가 있다.",[286,2307,2309],{"className":288,"code":2308,"language":290,"meta":291,"style":291},"@Transactional\npublic void changeName(Long userId) {\n\n    User user = userRepository.findById(userId)\n        .orElseThrow();\n\n    user.changeName(\"두부\");\n}\n",[293,2310,2311,2317,2335,2339,2363,2373,2377,2395],{"__ignoreMap":291},[296,2312,2313,2315],{"class":298,"line":299},[296,2314,303],{"class":302},[296,2316,1704],{"class":306},[296,2318,2319,2321,2323,2325,2327,2329,2331,2333],{"class":298,"line":310},[296,2320,476],{"class":306},[296,2322,1711],{"class":306},[296,2324,1714],{"class":683},[296,2326,687],{"class":302},[296,2328,1719],{"class":306},[296,2330,1722],{"class":319},[296,2332,1725],{"class":302},[296,2334,486],{"class":302},[296,2336,2337],{"class":298,"line":489},[296,2338,493],{"emptyLinePlaceholder":492},[296,2340,2341,2343,2345,2347,2350,2352,2355,2357,2360],{"class":298,"line":496},[296,2342,1736],{"class":306},[296,2344,857],{"class":319},[296,2346,860],{"class":302},[296,2348,2349],{"class":319}," userRepository",[296,2351,680],{"class":302},[296,2353,2354],{"class":683},"findById",[296,2356,687],{"class":302},[296,2358,2359],{"class":319},"userId",[296,2361,2362],{"class":302},")\n",[296,2364,2365,2368,2371],{"class":298,"line":504},[296,2366,2367],{"class":302},"        .",[296,2369,2370],{"class":683},"orElseThrow",[296,2372,1423],{"class":302},[296,2374,2375],{"class":298,"line":516},[296,2376,493],{"emptyLinePlaceholder":492},[296,2378,2379,2381,2383,2385,2387,2389,2391,2393],{"class":298,"line":521},[296,2380,1769],{"class":319},[296,2382,680],{"class":302},[296,2384,1774],{"class":683},[296,2386,687],{"class":302},[296,2388,1216],{"class":302},[296,2390,1781],{"class":1219},[296,2392,1216],{"class":302},[296,2394,705],{"class":302},[296,2396,2397],{"class":298,"line":644},[296,2398,524],{"class":302},[282,2400,2401],{},"흐름을 단순화하면:",[286,2403,2406],{"className":2404,"code":2405,"language":365,"meta":291},[363],"Transaction 시작\n\n        ↓\n\nPersistence Context 생성\u002F참여\n\n        ↓\n\nEntity 조회\n\n        ↓\n\nEntity 변경\n\n        ↓\n\nDirty Checking\n\n        ↓\n\nFlush\n\n        ↓\n\nUPDATE SQL\n\n        ↓\n\nTransaction Commit\n",[293,2407,2405],{"__ignoreMap":291},[282,2409,2410,2411,2414],{},"이 구조를 이해하면 왜 별도의 ",[293,2412,2413],{},"save()"," 호출 없이 엔티티 변경사항이 반영되는지 이해할 수 있다.",[443,2416],{},[277,2418,2420],{"id":2419},"_23-persistencecontext와-transaction의-관계","🔗 23. @PersistenceContext와 Transaction의 관계",[282,2422,2423],{},"다시 처음의 코드로 돌아가 보자.",[286,2425,2426],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,2427,2428,2434],{"__ignoreMap":291},[296,2429,2430,2432],{"class":298,"line":299},[296,2431,303],{"class":302},[296,2433,307],{"class":306},[296,2435,2436,2438,2440,2442],{"class":298,"line":310},[296,2437,313],{"class":306},[296,2439,316],{"class":306},[296,2441,320],{"class":319},[296,2443,323],{"class":302},[282,2445,2446],{},"이 EntityManager는 단순히 애플리케이션 전체에서 하나의 객체를 공유하는 방식으로 생각하면 안 된다.",[282,2448,2449,2450,2453],{},"Spring이 JPA EntityManager를 관리하면서 ",[347,2451,2452],{},"현재 트랜잭션과 연결된 영속성 컨텍스트를 사용할 수 있도록 구성","한다.",[282,2455,2456],{},"따라서 같은 트랜잭션 안에서:",[286,2458,2459],{"className":288,"code":670,"language":290,"meta":291,"style":291},[293,2460,2461],{"__ignoreMap":291},[296,2462,2463,2465,2467,2469,2471,2473,2475,2477,2479,2481],{"class":298,"line":299},[296,2464,677],{"class":319},[296,2466,680],{"class":302},[296,2468,684],{"class":683},[296,2470,687],{"class":302},[296,2472,690],{"class":319},[296,2474,680],{"class":302},[296,2476,695],{"class":319},[296,2478,698],{"class":302},[296,2480,702],{"class":701},[296,2482,705],{"class":302},[282,2484,2485],{},"와 같은 작업을 수행하면 해당 트랜잭션의 영속성 컨텍스트를 통해 엔티티가 관리된다.",[282,2487,2488,2489,2491],{},"이 때문에 ",[293,2490,334],{},"를 사용할 때는 단순히 객체 하나를 주입받았다고 생각하기보다는:",[286,2493,2496],{"className":2494,"code":2495,"language":365,"meta":291},[363],"Spring\n\n↓\n\nEntityManager 관리\n\n↓\n\nTransaction\n\n↓\n\nPersistence Context\n\n↓\n\nEntity 관리\n",[293,2497,2495],{"__ignoreMap":291},[282,2499,2500],{},"관계를 이해하는 것이 중요하다.",[443,2502],{},[277,2504,2506],{"id":2505},"_24-entitymanager는-thread-safe한가","🧩 24. EntityManager는 Thread Safe한가?",[282,2508,2509],{},"여기서 또 하나 중요한 점이 있다.",[282,2511,2512,2513],{},"JPA의 EntityManager는 일반적으로 ",[347,2514,2515],{},"Thread Safe한 객체가 아니다.",[282,2517,2518],{},"따라서 여러 스레드에서 하나의 EntityManager 인스턴스를 직접 공유하는 방식으로 사용하면 안 된다.",[282,2520,2521],{},"하지만 Spring에서:",[286,2523,2524],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,2525,2526,2532],{"__ignoreMap":291},[296,2527,2528,2530],{"class":298,"line":299},[296,2529,303],{"class":302},[296,2531,307],{"class":306},[296,2533,2534,2536,2538,2540],{"class":298,"line":310},[296,2535,313],{"class":306},[296,2537,316],{"class":306},[296,2539,320],{"class":319},[296,2541,323],{"class":302},[282,2543,2544],{},"처럼 주입받아 사용하는 경우에는 개발자가 직접 EntityManager의 생명주기를 관리하는 것이 아니다.",[282,2546,2547],{},"Spring이 적절한 방식으로 EntityManager를 관리하고 현재 트랜잭션에 연결된 EntityManager를 사용할 수 있도록 처리한다.",[282,2549,2550],{},"따라서 개발자는 일반적으로 다음과 같이 사용한다.",[286,2552,2553],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,2554,2555,2561],{"__ignoreMap":291},[296,2556,2557,2559],{"class":298,"line":299},[296,2558,303],{"class":302},[296,2560,307],{"class":306},[296,2562,2563,2565,2567,2569],{"class":298,"line":310},[296,2564,313],{"class":306},[296,2566,316],{"class":306},[296,2568,320],{"class":319},[296,2570,323],{"class":302},[282,2572,1035],{},[286,2574,2576],{"className":288,"code":2575,"language":290,"meta":291,"style":291},"@Transactional\npublic void updateUser(Long userId) {\n\n    User user = entityManager.find(User.class, userId);\n\n    user.changeName(\"두부\");\n}\n",[293,2577,2578,2584,2603,2607,2635,2639,2657],{"__ignoreMap":291},[296,2579,2580,2582],{"class":298,"line":299},[296,2581,303],{"class":302},[296,2583,1704],{"class":306},[296,2585,2586,2588,2590,2593,2595,2597,2599,2601],{"class":298,"line":310},[296,2587,476],{"class":306},[296,2589,1711],{"class":306},[296,2591,2592],{"class":683}," updateUser",[296,2594,687],{"class":302},[296,2596,1719],{"class":306},[296,2598,1722],{"class":319},[296,2600,1725],{"class":302},[296,2602,486],{"class":302},[296,2604,2605],{"class":298,"line":489},[296,2606,493],{"emptyLinePlaceholder":492},[296,2608,2609,2611,2613,2615,2617,2619,2621,2623,2625,2627,2629,2631,2633],{"class":298,"line":496},[296,2610,1736],{"class":306},[296,2612,857],{"class":319},[296,2614,860],{"class":302},[296,2616,320],{"class":319},[296,2618,680],{"class":302},[296,2620,684],{"class":683},[296,2622,687],{"class":302},[296,2624,690],{"class":319},[296,2626,680],{"class":302},[296,2628,695],{"class":319},[296,2630,698],{"class":302},[296,2632,1722],{"class":319},[296,2634,705],{"class":302},[296,2636,2637],{"class":298,"line":504},[296,2638,493],{"emptyLinePlaceholder":492},[296,2640,2641,2643,2645,2647,2649,2651,2653,2655],{"class":298,"line":516},[296,2642,1769],{"class":319},[296,2644,680],{"class":302},[296,2646,1774],{"class":683},[296,2648,687],{"class":302},[296,2650,1216],{"class":302},[296,2652,1781],{"class":1219},[296,2654,1216],{"class":302},[296,2656,705],{"class":302},[296,2658,2659],{"class":298,"line":521},[296,2660,524],{"class":302},[282,2662,2663],{},"처럼 비즈니스 로직을 작성한다.",[443,2665],{},[277,2667,2669],{"id":2668},"_25-merge는-save와-같은-것일까","🔎 25. merge()는 save()와 같은 것일까?",[282,2671,2672,2673,2675],{},"EntityManager를 사용하다 보면 ",[293,2674,431],{},"도 자주 접하게 된다.",[286,2677,2679],{"className":288,"code":2678,"language":290,"meta":291,"style":291},"entityManager.merge(user);\n",[293,2680,2681],{"__ignoreMap":291},[296,2682,2683,2685,2687,2690,2692,2694],{"class":298,"line":299},[296,2684,677],{"class":319},[296,2686,680],{"class":302},[296,2688,2689],{"class":683},"merge",[296,2691,687],{"class":302},[296,2693,730],{"class":319},[296,2695,705],{"class":302},[282,2697,1648,2698,2700],{},[293,2699,431],{},"를 단순히:",[286,2702,2705],{"className":2703,"code":2704,"language":365,"meta":291},[363],"save()\n",[293,2706,2704],{"__ignoreMap":291},[282,2708,2709],{},"와 동일한 개념으로 생각하면 안 된다.",[282,2711,2712,1651,2714,935],{},[293,2713,431],{},[347,2715,2716],{},"준영속 상태의 엔티티 데이터를 새로운 영속 엔티티에 병합하는 것",[282,2718,2719,2720,2722],{},"중요한 점은 ",[293,2721,431],{},"가 전달받은 객체 자체를 다시 영속 상태로 만드는 것이 아니라는 것이다.",[282,2724,2124],{},[286,2726,2729],{"className":2727,"code":2728,"language":365,"meta":291},[363],"Detached Entity\n      │\n      │ merge()\n      ▼\n새로운 Managed Entity\n      │\n      ▼\nPersistence Context\n",[293,2730,2728],{"__ignoreMap":291},[282,2732,2733],{},"구조가 된다.",[282,2735,2736,2737,2739],{},"따라서 ",[293,2738,431],{}," 이후에는 반환된 엔티티를 사용하는 것이 중요하다.",[286,2741,2743],{"className":288,"code":2742,"language":290,"meta":291,"style":291},"User managedUser = entityManager.merge(user);\n",[293,2744,2745],{"__ignoreMap":291},[296,2746,2747,2749,2752,2754,2756,2758,2760,2762,2764],{"class":298,"line":299},[296,2748,690],{"class":306},[296,2750,2751],{"class":319}," managedUser ",[296,2753,860],{"class":302},[296,2755,320],{"class":319},[296,2757,680],{"class":302},[296,2759,2689],{"class":683},[296,2761,687],{"class":302},[296,2763,730],{"class":319},[296,2765,705],{"class":302},[443,2767],{},[277,2769,2771],{"id":2770},"️-26-merge를-무조건-사용할-필요는-없다","⚠️ 26. merge()를 무조건 사용할 필요는 없다",[282,2773,2774,2775,2777],{},"Spring Data JPA를 사용하다 보면 ",[293,2776,431],{},"를 직접 호출할 일이 생각보다 많지 않다.",[282,2779,2780],{},"특히 일반적인 서비스 로직에서는:",[286,2782,2784],{"className":288,"code":2783,"language":290,"meta":291,"style":291},"@Transactional\npublic void updateUser(Long userId, String name) {\n\n    User user = userRepository.findById(userId)\n        .orElseThrow();\n\n    user.changeName(name);\n}\n",[293,2785,2786,2792,2816,2820,2840,2848,2852,2867],{"__ignoreMap":291},[296,2787,2788,2790],{"class":298,"line":299},[296,2789,303],{"class":302},[296,2791,1704],{"class":306},[296,2793,2794,2796,2798,2800,2802,2804,2806,2808,2810,2812,2814],{"class":298,"line":310},[296,2795,476],{"class":306},[296,2797,1711],{"class":306},[296,2799,2592],{"class":683},[296,2801,687],{"class":302},[296,2803,1719],{"class":306},[296,2805,1722],{"class":319},[296,2807,698],{"class":302},[296,2809,649],{"class":306},[296,2811,652],{"class":319},[296,2813,1725],{"class":302},[296,2815,486],{"class":302},[296,2817,2818],{"class":298,"line":489},[296,2819,493],{"emptyLinePlaceholder":492},[296,2821,2822,2824,2826,2828,2830,2832,2834,2836,2838],{"class":298,"line":496},[296,2823,1736],{"class":306},[296,2825,857],{"class":319},[296,2827,860],{"class":302},[296,2829,2349],{"class":319},[296,2831,680],{"class":302},[296,2833,2354],{"class":683},[296,2835,687],{"class":302},[296,2837,2359],{"class":319},[296,2839,2362],{"class":302},[296,2841,2842,2844,2846],{"class":298,"line":504},[296,2843,2367],{"class":302},[296,2845,2370],{"class":683},[296,2847,1423],{"class":302},[296,2849,2850],{"class":298,"line":516},[296,2851,493],{"emptyLinePlaceholder":492},[296,2853,2854,2856,2858,2860,2862,2865],{"class":298,"line":521},[296,2855,1769],{"class":319},[296,2857,680],{"class":302},[296,2859,1774],{"class":683},[296,2861,687],{"class":302},[296,2863,2864],{"class":319},"name",[296,2866,705],{"class":302},[296,2868,2869],{"class":298,"line":644},[296,2870,524],{"class":302},[282,2872,2873],{},"처럼 현재 트랜잭션의 영속성 컨텍스트에서 엔티티를 조회하고 상태를 변경하는 방식이 더 자연스럽다.",[282,2875,553],{},[286,2877,2880],{"className":2878,"code":2879,"language":365,"meta":291},[363],"조회\n\n↓\n\n영속 상태\n\n↓\n\n상태 변경\n\n↓\n\nDirty Checking\n\n↓\n\nFlush\n",[293,2881,2879],{"__ignoreMap":291},[282,2883,2884],{},"구조를 활용하는 것이다.",[443,2886],{},[277,2888,2890],{"id":2889},"_27-spring-data-jpa에서는-persistencecontext를-왜-잘-안-볼까","📦 27. Spring Data JPA에서는 @PersistenceContext를 왜 잘 안 볼까?",[282,2892,2893],{},"Spring Boot 프로젝트를 처음 시작하면 다음과 같은 코드를 많이 사용한다.",[286,2895,2897],{"className":288,"code":2896,"language":290,"meta":291,"style":291},"public interface UserRepository\n    extends JpaRepository\u003CUser, Long> {\n}\n",[293,2898,2899,2909,2929],{"__ignoreMap":291},[296,2900,2901,2903,2906],{"class":298,"line":299},[296,2902,476],{"class":306},[296,2904,2905],{"class":306}," interface",[296,2907,2908],{"class":482}," UserRepository\n",[296,2910,2911,2914,2917,2919,2921,2923,2925,2927],{"class":298,"line":310},[296,2912,2913],{"class":306},"    extends",[296,2915,2916],{"class":482}," JpaRepository",[296,2918,2229],{"class":302},[296,2920,690],{"class":306},[296,2922,698],{"class":302},[296,2924,632],{"class":306},[296,2926,2234],{"class":302},[296,2928,486],{"class":302},[296,2930,2931],{"class":298,"line":489},[296,2932,524],{"class":302},[282,2934,2935],{},"이 경우 개발자가 직접:",[286,2937,2938],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,2939,2940,2946],{"__ignoreMap":291},[296,2941,2942,2944],{"class":298,"line":299},[296,2943,303],{"class":302},[296,2945,307],{"class":306},[296,2947,2948,2950,2952,2954],{"class":298,"line":310},[296,2949,313],{"class":306},[296,2951,316],{"class":306},[296,2953,320],{"class":319},[296,2955,323],{"class":302},[282,2957,2958],{},"를 작성하지 않아도:",[286,2960,2962],{"className":288,"code":2961,"language":290,"meta":291,"style":291},"userRepository.findById(id);\n\nuserRepository.save(user);\n\nuserRepository.delete(user);\n",[293,2963,2964,2980,2984,2998,3002],{"__ignoreMap":291},[296,2965,2966,2969,2971,2973,2975,2978],{"class":298,"line":299},[296,2967,2968],{"class":319},"userRepository",[296,2970,680],{"class":302},[296,2972,2354],{"class":683},[296,2974,687],{"class":302},[296,2976,2977],{"class":319},"id",[296,2979,705],{"class":302},[296,2981,2982],{"class":298,"line":310},[296,2983,493],{"emptyLinePlaceholder":492},[296,2985,2986,2988,2990,2992,2994,2996],{"class":298,"line":489},[296,2987,2968],{"class":319},[296,2989,680],{"class":302},[296,2991,1806],{"class":683},[296,2993,687],{"class":302},[296,2995,730],{"class":319},[296,2997,705],{"class":302},[296,2999,3000],{"class":298,"line":496},[296,3001,493],{"emptyLinePlaceholder":492},[296,3003,3004,3006,3008,3011,3013,3015],{"class":298,"line":504},[296,3005,2968],{"class":319},[296,3007,680],{"class":302},[296,3009,3010],{"class":683},"delete",[296,3012,687],{"class":302},[296,3014,730],{"class":319},[296,3016,705],{"class":302},[282,3018,3019],{},"같은 기능을 사용할 수 있다.",[282,3021,3022],{},"그 이유는 Spring Data JPA가 내부적으로 EntityManager를 활용해 Repository 기능을 구현하기 때문이다.",[282,3024,553],{},[286,3026,3029],{"className":3027,"code":3028,"language":365,"meta":291},[363],"Application\n\n↓\n\nUserRepository\n\n↓\n\nSpring Data JPA\n\n↓\n\nEntityManager\n\n↓\n\nPersistence Context\n\n↓\n\nDatabase\n",[293,3030,3028],{"__ignoreMap":291},[282,3032,3033],{},"구조로 연결된다.",[282,3035,2736,3036,3039],{},[293,3037,3038],{},"JpaRepository","를 사용하는 일반적인 CRUD에서는 EntityManager를 직접 다룰 필요가 많지 않다.",[443,3041],{},[277,3043,3045],{"id":3044},"️-28-그렇다면-entitymanager를-직접-사용하는-이유는","🛠️ 28. 그렇다면 EntityManager를 직접 사용하는 이유는?",[282,3047,3048],{},"Spring Data JPA가 대부분의 CRUD 기능을 제공하지만 EntityManager를 직접 사용하는 경우도 있다.",[282,3050,3051],{},"대표적인 경우는:",[286,3053,3056],{"className":3054,"code":3055,"language":365,"meta":291},[363],"복잡한 동적 쿼리\n\nBulk 처리\n\nPersistence Context 제어\n\nFlush \u002F Clear 직접 제어\n\nJPA 자체 기능 사용\n\nQueryDSL과 함께 세밀한 처리\n",[293,3057,3055],{"__ignoreMap":291},[282,3059,3060],{},"등이다.",[282,3062,3063],{},"예를 들어 대량 데이터를 처리한 뒤 영속성 컨텍스트를 비우고 싶다면:",[286,3065,3067],{"className":288,"code":3066,"language":290,"meta":291,"style":291},"entityManager.flush();\nentityManager.clear();\n",[293,3068,3069,3080],{"__ignoreMap":291},[296,3070,3071,3073,3075,3078],{"class":298,"line":299},[296,3072,677],{"class":319},[296,3074,680],{"class":302},[296,3076,3077],{"class":683},"flush",[296,3079,1423],{"class":302},[296,3081,3082,3084,3086,3088],{"class":298,"line":310},[296,3083,677],{"class":319},[296,3085,680],{"class":302},[296,3087,1420],{"class":683},[296,3089,1423],{"class":302},[282,3091,3092],{},"를 사용할 수 있다.",[443,3094],{},[277,3096,3098],{"id":3097},"_29-flush와-clear를-함께-사용하는-경우","🧹 29. flush()와 clear()를 함께 사용하는 경우",[282,3100,3101],{},"대량 데이터를 반복해서 처리한다고 생각해보자.",[286,3103,3105],{"className":288,"code":3104,"language":290,"meta":291,"style":291},"for (int i = 0; i \u003C 10000; i++) {\n\n    User user = new User(...);\n\n    entityManager.persist(user);\n}\n",[293,3106,3107,3146,3150,3165,3169,3184],{"__ignoreMap":291},[296,3108,3109,3112,3115,3118,3121,3123,3126,3129,3131,3133,3136,3138,3141,3144],{"class":298,"line":299},[296,3110,3111],{"class":1208},"for",[296,3113,3114],{"class":302}," (",[296,3116,3117],{"class":306},"int",[296,3119,3120],{"class":319}," i ",[296,3122,860],{"class":302},[296,3124,3125],{"class":701}," 0",[296,3127,3128],{"class":302},";",[296,3130,3120],{"class":319},[296,3132,2229],{"class":302},[296,3134,3135],{"class":701}," 10000",[296,3137,3128],{"class":302},[296,3139,3140],{"class":319}," i",[296,3142,3143],{"class":302},"++)",[296,3145,486],{"class":302},[296,3147,3148],{"class":298,"line":310},[296,3149,493],{"emptyLinePlaceholder":492},[296,3151,3152,3154,3156,3158,3160,3162],{"class":298,"line":489},[296,3153,1736],{"class":306},[296,3155,857],{"class":319},[296,3157,860],{"class":302},[296,3159,1209],{"class":1208},[296,3161,605],{"class":683},[296,3163,3164],{"class":302},"(...);\n",[296,3166,3167],{"class":298,"line":496},[296,3168,493],{"emptyLinePlaceholder":492},[296,3170,3171,3174,3176,3178,3180,3182],{"class":298,"line":504},[296,3172,3173],{"class":319},"    entityManager",[296,3175,680],{"class":302},[296,3177,725],{"class":683},[296,3179,687],{"class":302},[296,3181,730],{"class":319},[296,3183,705],{"class":302},[296,3185,3186],{"class":298,"line":516},[296,3187,524],{"class":302},[282,3189,3190],{},"이런 방식으로 많은 엔티티를 하나의 영속성 컨텍스트에서 계속 관리하면 메모리 부담이 커질 수 있다.",[282,3192,3193],{},"이런 상황에서는:",[286,3195,3196],{"className":288,"code":3066,"language":290,"meta":291,"style":291},[293,3197,3198,3208],{"__ignoreMap":291},[296,3199,3200,3202,3204,3206],{"class":298,"line":299},[296,3201,677],{"class":319},[296,3203,680],{"class":302},[296,3205,3077],{"class":683},[296,3207,1423],{"class":302},[296,3209,3210,3212,3214,3216],{"class":298,"line":310},[296,3211,677],{"class":319},[296,3213,680],{"class":302},[296,3215,1420],{"class":683},[296,3217,1423],{"class":302},[282,3219,3220],{},"를 적절한 단위로 사용하는 방법을 고려할 수 있다.",[282,3222,1383],{},[286,3224,3227],{"className":3225,"code":3226,"language":365,"meta":291},[363],"1000건 처리\n\n↓\n\nflush()\n\n↓\n\nDB 반영\n\n↓\n\nclear()\n\n↓\n\nPersistence Context 초기화\n\n↓\n\n다음 1000건\n",[293,3228,3226],{"__ignoreMap":291},[282,3230,3231],{},"다만 실제로는 데이터 규모와 트랜잭션 구조, 배치 처리 방식 등을 함께 고려해야 한다.",[443,3233],{},[277,3235,3237],{"id":3236},"_30-jpql과-entitymanager","🔥 30. JPQL과 EntityManager",[282,3239,3240],{},"EntityManager를 사용하면 JPQL을 직접 실행할 수도 있다.",[282,3242,1383],{},[286,3244,3246],{"className":288,"code":3245,"language":290,"meta":291,"style":291},"List\u003CUser> users = entityManager\n    .createQuery(\n        \"select u from User u where u.name = :name\",\n        User.class\n    )\n    .setParameter(\"name\", \"콩이\")\n    .getResultList();\n",[293,3247,3248,3264,3272,3283,3291,3295,3321],{"__ignoreMap":291},[296,3249,3250,3252,3254,3256,3258,3260,3262],{"class":298,"line":299},[296,3251,2226],{"class":306},[296,3253,2229],{"class":302},[296,3255,690],{"class":306},[296,3257,2234],{"class":302},[296,3259,2237],{"class":319},[296,3261,860],{"class":302},[296,3263,2242],{"class":319},[296,3265,3266,3268,3270],{"class":298,"line":310},[296,3267,2247],{"class":302},[296,3269,2250],{"class":683},[296,3271,2253],{"class":302},[296,3273,3274,3276,3279,3281],{"class":298,"line":489},[296,3275,2258],{"class":302},[296,3277,3278],{"class":1219},"select u from User u where u.name = :name",[296,3280,1216],{"class":302},[296,3282,2266],{"class":302},[296,3284,3285,3287,3289],{"class":298,"line":496},[296,3286,2271],{"class":319},[296,3288,680],{"class":302},[296,3290,2276],{"class":319},[296,3292,3293],{"class":298,"line":504},[296,3294,2281],{"class":302},[296,3296,3297,3299,3302,3304,3306,3308,3310,3312,3315,3317,3319],{"class":298,"line":516},[296,3298,2247],{"class":302},[296,3300,3301],{"class":683},"setParameter",[296,3303,687],{"class":302},[296,3305,1216],{"class":302},[296,3307,2864],{"class":1219},[296,3309,1216],{"class":302},[296,3311,698],{"class":302},[296,3313,3314],{"class":302}," \"",[296,3316,1220],{"class":1219},[296,3318,1216],{"class":302},[296,3320,2362],{"class":302},[296,3322,3323,3325,3327],{"class":298,"line":521},[296,3324,2247],{"class":302},[296,3326,2288],{"class":683},[296,3328,1423],{"class":302},[282,3330,3331,3332,935],{},"여기서 중요한 점은 JPQL이 테이블이 아니라 ",[347,3333,3334],{},"엔티티를 대상으로 작성된다는 것",[282,3336,3337],{},"SQL에서는:",[286,3339,3343],{"className":3340,"code":3341,"language":3342,"meta":291,"style":291},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","SELECT *\nFROM users\nWHERE name = ?\n","sql",[293,3344,3345,3350,3355],{"__ignoreMap":291},[296,3346,3347],{"class":298,"line":299},[296,3348,3349],{},"SELECT *\n",[296,3351,3352],{"class":298,"line":310},[296,3353,3354],{},"FROM users\n",[296,3356,3357],{"class":298,"line":489},[296,3358,3359],{},"WHERE name = ?\n",[282,3361,3362],{},"처럼 테이블을 기준으로 생각한다.",[282,3364,3365],{},"반면 JPQL에서는:",[286,3367,3369],{"className":288,"code":3368,"language":290,"meta":291,"style":291},"select u\nfrom User u\nwhere u.name = :name\n",[293,3370,3371,3376,3386],{"__ignoreMap":291},[296,3372,3373],{"class":298,"line":299},[296,3374,3375],{"class":319},"select u\n",[296,3377,3378,3381,3383],{"class":298,"line":310},[296,3379,3380],{"class":319},"from ",[296,3382,690],{"class":306},[296,3384,3385],{"class":319}," u\n",[296,3387,3388,3391,3393,3396,3398,3401],{"class":298,"line":489},[296,3389,3390],{"class":319},"where u",[296,3392,680],{"class":302},[296,3394,3395],{"class":319},"name ",[296,3397,860],{"class":302},[296,3399,3400],{"class":1208}," :",[296,3402,3403],{"class":319},"name\n",[282,3405,3406],{},"처럼 엔티티와 필드를 기준으로 작성한다.",[282,3408,3409],{},"JPA는 이를 SQL로 변환해 데이터베이스에 전달한다.",[443,3411],{},[277,3413,3415],{"id":3414},"_31-entitymanager와-querydsl의-관계","🧠 31. EntityManager와 QueryDSL의 관계",[282,3417,3418],{},"QueryDSL을 사용하는 프로젝트에서도 EntityManager는 내부적으로 중요한 역할을 한다.",[282,3420,3421],{},"QueryDSL JPA에서는 일반적으로:",[286,3423,3425],{"className":288,"code":3424,"language":290,"meta":291,"style":291},"JPAQueryFactory queryFactory;\n",[293,3426,3427],{"__ignoreMap":291},[296,3428,3429,3432,3435],{"class":298,"line":299},[296,3430,3431],{"class":306},"JPAQueryFactory",[296,3433,3434],{"class":319}," queryFactory",[296,3436,323],{"class":302},[282,3438,3439],{},"를 통해 쿼리를 작성한다.",[282,3441,1383],{},[286,3443,3445],{"className":288,"code":3444,"language":290,"meta":291,"style":291},"queryFactory\n    .selectFrom(user)\n    .where(user.name.eq(\"콩이\"))\n    .fetch();\n",[293,3446,3447,3452,3465,3496],{"__ignoreMap":291},[296,3448,3449],{"class":298,"line":299},[296,3450,3451],{"class":319},"queryFactory\n",[296,3453,3454,3456,3459,3461,3463],{"class":298,"line":310},[296,3455,2247],{"class":302},[296,3457,3458],{"class":683},"selectFrom",[296,3460,687],{"class":302},[296,3462,730],{"class":319},[296,3464,2362],{"class":302},[296,3466,3467,3469,3472,3474,3476,3478,3480,3482,3485,3487,3489,3491,3493],{"class":298,"line":489},[296,3468,2247],{"class":302},[296,3470,3471],{"class":683},"where",[296,3473,687],{"class":302},[296,3475,730],{"class":319},[296,3477,680],{"class":302},[296,3479,2864],{"class":319},[296,3481,680],{"class":302},[296,3483,3484],{"class":683},"eq",[296,3486,687],{"class":302},[296,3488,1216],{"class":302},[296,3490,1220],{"class":1219},[296,3492,1216],{"class":302},[296,3494,3495],{"class":302},"))\n",[296,3497,3498,3500,3503],{"class":298,"line":496},[296,3499,2247],{"class":302},[296,3501,3502],{"class":683},"fetch",[296,3504,1423],{"class":302},[282,3506,3507],{},"여기서 QueryDSL이 직접 데이터베이스와 통신하는 것이 아니라 JPA의 EntityManager를 기반으로 쿼리를 실행한다.",[282,3509,2124],{},[286,3511,3514],{"className":3512,"code":3513,"language":365,"meta":291},[363],"QueryDSL\n\n↓\n\nJPAQueryFactory\n\n↓\n\nEntityManager\n\n↓\n\nJPA\n\n↓\n\nDatabase\n",[293,3515,3513],{"__ignoreMap":291},[282,3517,3518],{},"라고 볼 수 있다.",[282,3520,3521,3522,3524],{},"따라서 QueryDSL을 사용하고 있다면 ",[293,3523,334],{},"가 내부적으로 어떤 역할을 하고 있는지 이해해두는 것이 좋다.",[443,3526],{},[277,3528,3530],{"id":3529},"_32-persistencecontext와-autowired의-차이","🔎 32. @PersistenceContext와 @Autowired의 차이",[282,3532,3533],{},"Spring에서 의존성을 주입하다 보면 다음과 같은 코드도 생각할 수 있다.",[286,3535,3537],{"className":288,"code":3536,"language":290,"meta":291,"style":291},"@Autowired\nprivate EntityManager entityManager;\n",[293,3538,3539,3546],{"__ignoreMap":291},[296,3540,3541,3543],{"class":298,"line":299},[296,3542,303],{"class":302},[296,3544,3545],{"class":306},"Autowired\n",[296,3547,3548,3550,3552,3554],{"class":298,"line":310},[296,3549,313],{"class":306},[296,3551,316],{"class":306},[296,3553,320],{"class":319},[296,3555,323],{"class":302},[282,3557,3558],{},"그렇다면 왜 JPA에서는:",[286,3560,3561],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,3562,3563,3569],{"__ignoreMap":291},[296,3564,3565,3567],{"class":298,"line":299},[296,3566,303],{"class":302},[296,3568,307],{"class":306},[296,3570,3571,3573,3575,3577],{"class":298,"line":310},[296,3572,313],{"class":306},[296,3574,316],{"class":306},[296,3576,320],{"class":319},[296,3578,323],{"class":302},[282,3580,3581],{},"를 사용하는 것일까?",[282,3583,3584],{},"둘은 목적과 의미가 조금 다르다.",[282,3586,3587,3589,3590,2453],{},[293,3588,344],{},"는 JPA 표준에서 제공하는 어노테이션으로 ",[347,3591,3592],{},"Persistence Context와 관련된 EntityManager 주입을 표현",[282,3594,3595,3596,3599],{},"반면 ",[293,3597,3598],{},"@Autowired","는 Spring의 의존성 주입 기능이다.",[282,3601,553],{},[286,3603,3606],{"className":3604,"code":3605,"language":365,"meta":291},[363],"@PersistenceContext\n\n→ JPA 표준의 EntityManager 주입 의미\n",[293,3607,3605],{"__ignoreMap":291},[286,3609,3612],{"className":3610,"code":3611,"language":365,"meta":291},[363],"@Autowired\n\n→ Spring의 의존성 주입 의미\n",[293,3613,3611],{"__ignoreMap":291},[282,3615,3616],{},"로 구분할 수 있다.",[282,3618,3619],{},"실무에서는 Spring이 JPA의 EntityManager를 관리해주기 때문에 둘의 동작이 비슷하게 보일 수 있지만, 의미와 추상화 레벨은 다르다.",[443,3621],{},[277,3623,3625],{"id":3624},"_33-persistencecontext의-기본-사용-예","🧩 33. @PersistenceContext의 기본 사용 예",[282,3627,3628],{},"가장 전형적인 코드를 하나 만들어보자.",[286,3630,3632],{"className":288,"code":3631,"language":290,"meta":291,"style":291},"@Repository\npublic class UserRepository {\n\n    @PersistenceContext\n    private EntityManager entityManager;\n\n    public User findById(Long id) {\n\n        return entityManager.find(User.class, id);\n    }\n\n    public void save(User user) {\n\n        entityManager.persist(user);\n    }\n\n    public void delete(User user) {\n\n        entityManager.remove(user);\n    }\n}\n",[293,3633,3634,3640,3650,3654,3660,3670,3674,3695,3699,3724,3729,3734,3755,3760,3776,3781,3786,3806,3811,3826,3831],{"__ignoreMap":291},[296,3635,3636,3638],{"class":298,"line":299},[296,3637,303],{"class":302},[296,3639,471],{"class":306},[296,3641,3642,3644,3646,3648],{"class":298,"line":310},[296,3643,476],{"class":306},[296,3645,479],{"class":306},[296,3647,483],{"class":482},[296,3649,486],{"class":302},[296,3651,3652],{"class":298,"line":489},[296,3653,493],{"emptyLinePlaceholder":492},[296,3655,3656,3658],{"class":298,"line":496},[296,3657,499],{"class":302},[296,3659,307],{"class":306},[296,3661,3662,3664,3666,3668],{"class":298,"line":504},[296,3663,507],{"class":306},[296,3665,316],{"class":306},[296,3667,320],{"class":319},[296,3669,323],{"class":302},[296,3671,3672],{"class":298,"line":516},[296,3673,493],{"emptyLinePlaceholder":492},[296,3675,3676,3679,3681,3684,3686,3688,3691,3693],{"class":298,"line":521},[296,3677,3678],{"class":306},"    public",[296,3680,605],{"class":306},[296,3682,3683],{"class":683}," findById",[296,3685,687],{"class":302},[296,3687,1719],{"class":306},[296,3689,635],{"class":3690},"sHdIc",[296,3692,1725],{"class":302},[296,3694,486],{"class":302},[296,3696,3697],{"class":298,"line":644},[296,3698,493],{"emptyLinePlaceholder":492},[296,3700,3701,3704,3706,3708,3710,3712,3714,3716,3718,3720,3722],{"class":298,"line":657},[296,3702,3703],{"class":1208},"        return",[296,3705,320],{"class":319},[296,3707,680],{"class":302},[296,3709,684],{"class":683},[296,3711,687],{"class":302},[296,3713,690],{"class":319},[296,3715,680],{"class":302},[296,3717,695],{"class":319},[296,3719,698],{"class":302},[296,3721,635],{"class":319},[296,3723,705],{"class":302},[296,3725,3726],{"class":298,"line":662},[296,3727,3728],{"class":302},"    }\n",[296,3730,3732],{"class":298,"line":3731},11,[296,3733,493],{"emptyLinePlaceholder":492},[296,3735,3737,3739,3741,3744,3746,3748,3751,3753],{"class":298,"line":3736},12,[296,3738,3678],{"class":306},[296,3740,1711],{"class":306},[296,3742,3743],{"class":683}," save",[296,3745,687],{"class":302},[296,3747,690],{"class":306},[296,3749,3750],{"class":3690}," user",[296,3752,1725],{"class":302},[296,3754,486],{"class":302},[296,3756,3758],{"class":298,"line":3757},13,[296,3759,493],{"emptyLinePlaceholder":492},[296,3761,3763,3766,3768,3770,3772,3774],{"class":298,"line":3762},14,[296,3764,3765],{"class":319},"        entityManager",[296,3767,680],{"class":302},[296,3769,725],{"class":683},[296,3771,687],{"class":302},[296,3773,730],{"class":319},[296,3775,705],{"class":302},[296,3777,3779],{"class":298,"line":3778},15,[296,3780,3728],{"class":302},[296,3782,3784],{"class":298,"line":3783},16,[296,3785,493],{"emptyLinePlaceholder":492},[296,3787,3789,3791,3793,3796,3798,3800,3802,3804],{"class":298,"line":3788},17,[296,3790,3678],{"class":306},[296,3792,1711],{"class":306},[296,3794,3795],{"class":683}," delete",[296,3797,687],{"class":302},[296,3799,690],{"class":306},[296,3801,3750],{"class":3690},[296,3803,1725],{"class":302},[296,3805,486],{"class":302},[296,3807,3809],{"class":298,"line":3808},18,[296,3810,493],{"emptyLinePlaceholder":492},[296,3812,3814,3816,3818,3820,3822,3824],{"class":298,"line":3813},19,[296,3815,3765],{"class":319},[296,3817,680],{"class":302},[296,3819,749],{"class":683},[296,3821,687],{"class":302},[296,3823,730],{"class":319},[296,3825,705],{"class":302},[296,3827,3829],{"class":298,"line":3828},20,[296,3830,3728],{"class":302},[296,3832,3834],{"class":298,"line":3833},21,[296,3835,524],{"class":302},[282,3837,3838],{},"그리고 Service:",[286,3840,3842],{"className":288,"code":3841,"language":290,"meta":291,"style":291},"@Service\n@RequiredArgsConstructor\npublic class UserService {\n\n    private final UserRepository userRepository;\n\n    @Transactional\n    public void changeName(\n        Long userId,\n        String name\n    ) {\n\n        User user = userRepository.findById(userId);\n\n        user.changeName(name);\n    }\n}\n",[293,3843,3844,3851,3858,3869,3873,3886,3890,3896,3906,3915,3923,3930,3934,3954,3958,3973,3977],{"__ignoreMap":291},[296,3845,3846,3848],{"class":298,"line":299},[296,3847,303],{"class":302},[296,3849,3850],{"class":306},"Service\n",[296,3852,3853,3855],{"class":298,"line":310},[296,3854,303],{"class":302},[296,3856,3857],{"class":306},"RequiredArgsConstructor\n",[296,3859,3860,3862,3864,3867],{"class":298,"line":489},[296,3861,476],{"class":306},[296,3863,479],{"class":306},[296,3865,3866],{"class":482}," UserService",[296,3868,486],{"class":302},[296,3870,3871],{"class":298,"line":496},[296,3872,493],{"emptyLinePlaceholder":492},[296,3874,3875,3877,3880,3882,3884],{"class":298,"line":504},[296,3876,507],{"class":306},[296,3878,3879],{"class":306}," final",[296,3881,483],{"class":306},[296,3883,2349],{"class":319},[296,3885,323],{"class":302},[296,3887,3888],{"class":298,"line":516},[296,3889,493],{"emptyLinePlaceholder":492},[296,3891,3892,3894],{"class":298,"line":521},[296,3893,499],{"class":302},[296,3895,1704],{"class":306},[296,3897,3898,3900,3902,3904],{"class":298,"line":644},[296,3899,3678],{"class":306},[296,3901,1711],{"class":306},[296,3903,1714],{"class":683},[296,3905,2253],{"class":302},[296,3907,3908,3911,3913],{"class":298,"line":657},[296,3909,3910],{"class":306},"        Long",[296,3912,1722],{"class":3690},[296,3914,2266],{"class":302},[296,3916,3917,3920],{"class":298,"line":662},[296,3918,3919],{"class":306},"        String",[296,3921,3922],{"class":3690}," name\n",[296,3924,3925,3928],{"class":298,"line":3731},[296,3926,3927],{"class":302},"    )",[296,3929,486],{"class":302},[296,3931,3932],{"class":298,"line":3736},[296,3933,493],{"emptyLinePlaceholder":492},[296,3935,3936,3938,3940,3942,3944,3946,3948,3950,3952],{"class":298,"line":3757},[296,3937,2271],{"class":306},[296,3939,857],{"class":319},[296,3941,860],{"class":302},[296,3943,2349],{"class":319},[296,3945,680],{"class":302},[296,3947,2354],{"class":683},[296,3949,687],{"class":302},[296,3951,2359],{"class":319},[296,3953,705],{"class":302},[296,3955,3956],{"class":298,"line":3762},[296,3957,493],{"emptyLinePlaceholder":492},[296,3959,3960,3963,3965,3967,3969,3971],{"class":298,"line":3778},[296,3961,3962],{"class":319},"        user",[296,3964,680],{"class":302},[296,3966,1774],{"class":683},[296,3968,687],{"class":302},[296,3970,2864],{"class":319},[296,3972,705],{"class":302},[296,3974,3975],{"class":298,"line":3783},[296,3976,3728],{"class":302},[296,3978,3979],{"class":298,"line":3788},[296,3980,524],{"class":302},[282,3982,3983,3984,3986],{},"여기서 ",[293,3985,2413],{},"를 호출하지 않아도 변경사항이 반영될 수 있다.",[282,3988,3989],{},"왜냐하면:",[286,3991,3994],{"className":3992,"code":3993,"language":365,"meta":291},[363],"findById()\n\n↓\n\n영속성 컨텍스트에 Entity 등록\n\n↓\n\nuser.changeName()\n\n↓\n\nDirty Checking\n\n↓\n\nFlush\n\n↓\n\nUPDATE SQL\n",[293,3995,3993],{"__ignoreMap":291},[282,3997,3998],{},"이 발생하기 때문이다.",[443,4000],{},[277,4002,4004],{"id":4003},"️-34-transactional-없이-사용하면-어떻게-될까","⚠️ 34. @Transactional 없이 사용하면 어떻게 될까?",[282,4006,4007],{},"EntityManager를 사용하는 로직에서는 Transaction의 존재가 중요하다.",[282,4009,845],{},[286,4011,4013],{"className":288,"code":4012,"language":290,"meta":291,"style":291},"public void changeName(Long userId) {\n\n    User user = entityManager.find(User.class, userId);\n\n    user.changeName(\"두부\");\n}\n",[293,4014,4015,4033,4037,4065,4069,4087],{"__ignoreMap":291},[296,4016,4017,4019,4021,4023,4025,4027,4029,4031],{"class":298,"line":299},[296,4018,476],{"class":306},[296,4020,1711],{"class":306},[296,4022,1714],{"class":683},[296,4024,687],{"class":302},[296,4026,1719],{"class":306},[296,4028,1722],{"class":319},[296,4030,1725],{"class":302},[296,4032,486],{"class":302},[296,4034,4035],{"class":298,"line":310},[296,4036,493],{"emptyLinePlaceholder":492},[296,4038,4039,4041,4043,4045,4047,4049,4051,4053,4055,4057,4059,4061,4063],{"class":298,"line":489},[296,4040,1736],{"class":306},[296,4042,857],{"class":319},[296,4044,860],{"class":302},[296,4046,320],{"class":319},[296,4048,680],{"class":302},[296,4050,684],{"class":683},[296,4052,687],{"class":302},[296,4054,690],{"class":319},[296,4056,680],{"class":302},[296,4058,695],{"class":319},[296,4060,698],{"class":302},[296,4062,1722],{"class":319},[296,4064,705],{"class":302},[296,4066,4067],{"class":298,"line":496},[296,4068,493],{"emptyLinePlaceholder":492},[296,4070,4071,4073,4075,4077,4079,4081,4083,4085],{"class":298,"line":504},[296,4072,1769],{"class":319},[296,4074,680],{"class":302},[296,4076,1774],{"class":683},[296,4078,687],{"class":302},[296,4080,1216],{"class":302},[296,4082,1781],{"class":1219},[296,4084,1216],{"class":302},[296,4086,705],{"class":302},[296,4088,4089],{"class":298,"line":516},[296,4090,524],{"class":302},[282,4092,4093],{},"처럼 Transaction 없이 상태를 변경하려고 하면 JPA 작업의 종류와 실행 시점에 따라 문제가 발생할 수 있다.",[282,4095,4096],{},"특히:",[286,4098,4099],{"className":288,"code":714,"language":290,"meta":291,"style":291},[293,4100,4101],{"__ignoreMap":291},[296,4102,4103,4105,4107,4109,4111,4113],{"class":298,"line":299},[296,4104,677],{"class":319},[296,4106,680],{"class":302},[296,4108,725],{"class":683},[296,4110,687],{"class":302},[296,4112,730],{"class":319},[296,4114,705],{"class":302},[282,4116,4117],{},"와 같은 변경 작업은 일반적으로 활성화된 Transaction이 필요하다.",[282,4119,4120],{},"따라서 일반적인 서비스 계층에서는:",[286,4122,4124],{"className":288,"code":4123,"language":290,"meta":291,"style":291},"@Transactional\n",[293,4125,4126],{"__ignoreMap":291},[296,4127,4128,4130],{"class":298,"line":299},[296,4129,303],{"class":302},[296,4131,1704],{"class":306},[282,4133,4134],{},"을 통해 작업의 경계를 명확하게 설정한다.",[443,4136],{},[277,4138,4140],{"id":4139},"_35-하나의-transaction-안에서-일어나는-일","🔄 35. 하나의 Transaction 안에서 일어나는 일",[282,4142,4143],{},"다음 코드를 기준으로 생각해보자.",[286,4145,4147],{"className":288,"code":4146,"language":290,"meta":291,"style":291},"@Transactional\npublic void updateUser(\n    Long userId,\n    String name\n) {\n\n    User user = entityManager.find(\n        User.class,\n        userId\n    );\n\n    user.changeName(name);\n}\n",[293,4148,4149,4155,4165,4174,4181,4187,4191,4207,4217,4222,4227,4231,4245],{"__ignoreMap":291},[296,4150,4151,4153],{"class":298,"line":299},[296,4152,303],{"class":302},[296,4154,1704],{"class":306},[296,4156,4157,4159,4161,4163],{"class":298,"line":310},[296,4158,476],{"class":306},[296,4160,1711],{"class":306},[296,4162,2592],{"class":683},[296,4164,2253],{"class":302},[296,4166,4167,4170,4172],{"class":298,"line":489},[296,4168,4169],{"class":306},"    Long",[296,4171,1722],{"class":319},[296,4173,2266],{"class":302},[296,4175,4176,4179],{"class":298,"line":496},[296,4177,4178],{"class":306},"    String",[296,4180,3922],{"class":319},[296,4182,4183,4185],{"class":298,"line":504},[296,4184,1725],{"class":302},[296,4186,486],{"class":302},[296,4188,4189],{"class":298,"line":516},[296,4190,493],{"emptyLinePlaceholder":492},[296,4192,4193,4195,4197,4199,4201,4203,4205],{"class":298,"line":521},[296,4194,1736],{"class":306},[296,4196,857],{"class":319},[296,4198,860],{"class":302},[296,4200,320],{"class":319},[296,4202,680],{"class":302},[296,4204,684],{"class":683},[296,4206,2253],{"class":302},[296,4208,4209,4211,4213,4215],{"class":298,"line":644},[296,4210,2271],{"class":319},[296,4212,680],{"class":302},[296,4214,695],{"class":319},[296,4216,2266],{"class":302},[296,4218,4219],{"class":298,"line":657},[296,4220,4221],{"class":319},"        userId\n",[296,4223,4224],{"class":298,"line":662},[296,4225,4226],{"class":302},"    );\n",[296,4228,4229],{"class":298,"line":3731},[296,4230,493],{"emptyLinePlaceholder":492},[296,4232,4233,4235,4237,4239,4241,4243],{"class":298,"line":3736},[296,4234,1769],{"class":319},[296,4236,680],{"class":302},[296,4238,1774],{"class":683},[296,4240,687],{"class":302},[296,4242,2864],{"class":319},[296,4244,705],{"class":302},[296,4246,4247],{"class":298,"line":3757},[296,4248,524],{"class":302},[282,4250,4251],{},"내부적으로는 대략 다음과 같은 흐름이 만들어진다.",[286,4253,4256],{"className":4254,"code":4255,"language":365,"meta":291},[363],"Transaction 시작\n        │\n        ▼\nPersistence Context\n        │\n        ▼\nEntity 조회\n        │\n        ▼\nUser 영속 상태\n        │\n        ▼\nchangeName()\n        │\n        ▼\nDirty Checking\n        │\n        ▼\nFlush\n        │\n        ▼\nUPDATE SQL\n        │\n        ▼\nCommit\n",[293,4257,4255],{"__ignoreMap":291},[282,4259,4260],{},"이 구조가 바로 JPA를 사용하는 가장 중요한 기본 흐름 중 하나다.",[443,4262],{},[277,4264,4266],{"id":4265},"_36-persistencecontext를-이해할-때-핵심적으로-기억할-것","🧠 36. @PersistenceContext를 이해할 때 핵심적으로 기억할 것",[282,4268,4269,4271],{},[293,4270,344],{}," 자체에 너무 많은 의미를 부여할 필요는 없다.",[282,4273,4274],{},"중요한 것은 다음 관계를 이해하는 것이다.",[286,4276,4279],{"className":4277,"code":4278,"language":365,"meta":291},[363],"@PersistenceContext\n\n↓\n\nEntityManager\n\n↓\n\nPersistence Context\n\n↓\n\nEntity 상태 관리\n\n↓\n\nDirty Checking \u002F 1차 캐시 \u002F Flush\n\n↓\n\nTransaction\n\n↓\n\nDatabase\n",[293,4280,4278],{"__ignoreMap":291},[282,4282,553],{},[286,4284,4285],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,4286,4287,4293],{"__ignoreMap":291},[296,4288,4289,4291],{"class":298,"line":299},[296,4290,303],{"class":302},[296,4292,307],{"class":306},[296,4294,4295,4297,4299,4301],{"class":298,"line":310},[296,4296,313],{"class":306},[296,4298,316],{"class":306},[296,4300,320],{"class":319},[296,4302,323],{"class":302},[282,4304,4305],{},"를 보면 단순히:",[328,4307,4308],{},[282,4309,4310],{},"EntityManager를 주입받는구나.",[282,4312,4313],{},"에서 끝내지 않고:",[328,4315,4316],{},[282,4317,4318],{},"현재 JPA가 관리하는 영속성 컨텍스트와 상호작용하기 위한 EntityManager를 주입받는구나.",[282,4320,4321],{},"정도로 이해하면 좋다.",[443,4323],{},[277,4325,4327],{"id":4326},"_37-persistencecontext와-spring-data-jpa를-함께-정리하면","📝 37. @PersistenceContext와 Spring Data JPA를 함께 정리하면",[282,4329,4330],{},"Spring Data JPA를 사용하는 프로젝트에서는 대부분 다음과 같이 작성한다.",[286,4332,4333],{"className":288,"code":2896,"language":290,"meta":291,"style":291},[293,4334,4335,4343,4361],{"__ignoreMap":291},[296,4336,4337,4339,4341],{"class":298,"line":299},[296,4338,476],{"class":306},[296,4340,2905],{"class":306},[296,4342,2908],{"class":482},[296,4344,4345,4347,4349,4351,4353,4355,4357,4359],{"class":298,"line":310},[296,4346,2913],{"class":306},[296,4348,2916],{"class":482},[296,4350,2229],{"class":302},[296,4352,690],{"class":306},[296,4354,698],{"class":302},[296,4356,632],{"class":306},[296,4358,2234],{"class":302},[296,4360,486],{"class":302},[296,4362,4363],{"class":298,"line":489},[296,4364,524],{"class":302},[282,4366,1035],{},[286,4368,4369],{"className":288,"code":2961,"language":290,"meta":291,"style":291},[293,4370,4371,4385,4389,4403,4407],{"__ignoreMap":291},[296,4372,4373,4375,4377,4379,4381,4383],{"class":298,"line":299},[296,4374,2968],{"class":319},[296,4376,680],{"class":302},[296,4378,2354],{"class":683},[296,4380,687],{"class":302},[296,4382,2977],{"class":319},[296,4384,705],{"class":302},[296,4386,4387],{"class":298,"line":310},[296,4388,493],{"emptyLinePlaceholder":492},[296,4390,4391,4393,4395,4397,4399,4401],{"class":298,"line":489},[296,4392,2968],{"class":319},[296,4394,680],{"class":302},[296,4396,1806],{"class":683},[296,4398,687],{"class":302},[296,4400,730],{"class":319},[296,4402,705],{"class":302},[296,4404,4405],{"class":298,"line":496},[296,4406,493],{"emptyLinePlaceholder":492},[296,4408,4409,4411,4413,4415,4417,4419],{"class":298,"line":504},[296,4410,2968],{"class":319},[296,4412,680],{"class":302},[296,4414,3010],{"class":683},[296,4416,687],{"class":302},[296,4418,730],{"class":319},[296,4420,705],{"class":302},[282,4422,4423],{},"처럼 사용한다.",[282,4425,4426],{},"이 과정에서도 내부적으로는 JPA의 EntityManager와 Persistence Context가 동작한다.",[282,4428,4429],{},"즉 개발자가 직접 사용하지 않는다고 해서 EntityManager가 사라지는 것은 아니다.",[282,4431,4432],{},"오히려:",[286,4434,4437],{"className":4435,"code":4436,"language":365,"meta":291},[363],"Spring Data JPA\n\n→ EntityManager\n\n→ Persistence Context\n\n→ JPA\n\n→ Database\n",[293,4438,4436],{"__ignoreMap":291},[282,4440,4441],{},"구조를 추상화해서 개발자가 더 편하게 사용할 수 있도록 만든 것이다.",[443,4443],{},[277,4445,4447],{"id":4446},"_38-언제-persistencecontext를-직접-사용할까","🔎 38. 언제 @PersistenceContext를 직접 사용할까?",[282,4449,4450],{},"일반적인 CRUD에서는:",[286,4452,4454],{"className":288,"code":4453,"language":290,"meta":291,"style":291},"JpaRepository\n",[293,4455,4456],{"__ignoreMap":291},[296,4457,4458],{"class":298,"line":299},[296,4459,4453],{"class":306},[282,4461,4462],{},"만으로 충분한 경우가 많다.",[282,4464,4465],{},"하지만 다음과 같은 상황에서는 EntityManager를 직접 사용하는 것이 유용할 수 있다.",[286,4467,4470],{"className":4468,"code":4469,"language":365,"meta":291},[363],"복잡한 JPA 기능을 직접 제어해야 하는 경우\n\n↓\n\n영속성 컨텍스트를 직접 flush \u002F clear해야 하는 경우\n\n↓\n\nJPA 기반의 커스텀 Repository 구현\n\n↓\n\n특정 JPQL을 직접 실행해야 하는 경우\n\n↓\n\nBulk 작업 후 영속성 컨텍스트를 제어해야 하는 경우\n",[293,4471,4469],{"__ignoreMap":291},[282,4473,4474],{},"다만 EntityManager를 직접 사용한다고 해서 더 좋은 코드가 되는 것은 아니다.",[282,4476,4477,4478],{},"추상화가 제공하는 편리함을 포기하고 직접 제어하는 만큼, ",[347,4479,4480],{},"왜 직접 제어해야 하는지 이유가 명확해야 한다.",[443,4482],{},[277,4484,4486],{"id":4485},"마무리","🎯 마무리",[282,4488,4489,4491],{},[293,4490,344],{},"를 처음 접하면:",[286,4493,4494],{"className":288,"code":289,"language":290,"meta":291,"style":291},[293,4495,4496,4502],{"__ignoreMap":291},[296,4497,4498,4500],{"class":298,"line":299},[296,4499,303],{"class":302},[296,4501,307],{"class":306},[296,4503,4504,4506,4508,4510],{"class":298,"line":310},[296,4505,313],{"class":306},[296,4507,316],{"class":306},[296,4509,320],{"class":319},[296,4511,323],{"class":302},[282,4513,4514],{},"라는 한 줄만 기억하기 쉽다.",[282,4516,4517],{},"하지만 실제로 중요한 것은 이 한 줄 자체가 아니라 그 뒤에 있는 구조다.",[286,4519,4522],{"className":4520,"code":4521,"language":365,"meta":291},[363],"@PersistenceContext\n        ↓\nEntityManager\n        ↓\nPersistence Context\n        ↓\nEntity 상태 관리\n        ↓\nDirty Checking\n        ↓\nFlush\n        ↓\nTransaction\n        ↓\nDatabase\n",[293,4523,4521],{"__ignoreMap":291},[282,4525,4526,4528,4529,4531],{},[293,4527,344],{},"는 JPA가 관리하는 ",[293,4530,334],{},"를 주입받기 위한 JPA 표준 어노테이션이다.",[282,4533,4534,4535,4537,4538,947],{},"그리고 ",[293,4536,334],{},"는 엔티티를 직접 관리하기 위한 인터페이스이며, 실제 엔티티의 상태를 관리하는 중심에는 ",[347,4539,4540],{},"영속성 컨텍스트",[282,4542,4543],{},"영속성 컨텍스트를 이해하면 JPA에서 자주 등장하는 개념들도 자연스럽게 연결된다.",[286,4545,4548],{"className":4546,"code":4547,"language":365,"meta":291},[363],"find()\n ↓\n1차 캐시\n ↓\n영속 상태\n ↓\nDirty Checking\n ↓\nFlush\n ↓\nUPDATE\n",[293,4549,4547],{"__ignoreMap":291},[282,4551,711],{},[286,4553,4556],{"className":4554,"code":4555,"language":365,"meta":291},[363],"persist()\n ↓\n영속성 컨텍스트 등록\n ↓\nFlush\n ↓\nINSERT\n",[293,4557,4555],{"__ignoreMap":291},[282,4559,1035],{},[286,4561,4564],{"className":4562,"code":4563,"language":365,"meta":291},[363],"remove()\n ↓\n삭제 대상 등록\n ↓\nFlush\n ↓\nDELETE\n",[293,4565,4563],{"__ignoreMap":291},[282,4567,4568],{},"와 같은 JPA의 동작 방식도 이해할 수 있다.",[282,4570,4571,4572,4574],{},"특히 Spring Data JPA를 사용하는 환경에서는 ",[293,4573,334],{},"를 직접 호출하는 일이 많지 않기 때문에 오히려 내부 동작을 놓치기 쉽다.",[286,4576,4578],{"className":288,"code":4577,"language":290,"meta":291,"style":291},"userRepository.findById(id);\n\nuser.changeName(\"두부\");\n",[293,4579,4580,4594,4598],{"__ignoreMap":291},[296,4581,4582,4584,4586,4588,4590,4592],{"class":298,"line":299},[296,4583,2968],{"class":319},[296,4585,680],{"class":302},[296,4587,2354],{"class":683},[296,4589,687],{"class":302},[296,4591,2977],{"class":319},[296,4593,705],{"class":302},[296,4595,4596],{"class":298,"line":310},[296,4597,493],{"emptyLinePlaceholder":492},[296,4599,4600,4602,4604,4606,4608,4610,4612,4614],{"class":298,"line":489},[296,4601,730],{"class":319},[296,4603,680],{"class":302},[296,4605,1774],{"class":683},[296,4607,687],{"class":302},[296,4609,1216],{"class":302},[296,4611,1781],{"class":1219},[296,4613,1216],{"class":302},[296,4615,705],{"class":302},[282,4617,4618],{},"라는 간단한 코드 뒤에서도:",[286,4620,4623],{"className":4621,"code":4622,"language":365,"meta":291},[363],"Repository\n\n↓\n\nEntityManager\n\n↓\n\nPersistence Context\n\n↓\n\nDirty Checking\n\n↓\n\nFlush\n\n↓\n\nDatabase\n",[293,4624,4622],{"__ignoreMap":291},[282,4626,4627],{},"라는 과정이 동작하고 있다.",[282,4629,4630,4631,4633],{},"결국 ",[293,4632,344],{},"를 이해한다는 것은 단순히 어노테이션 하나를 외우는 것이 아니라,",[328,4635,4636],{},[282,4637,4638],{},[347,4639,4640],{},"JPA가 엔티티를 어떻게 관리하고, 언제 데이터베이스와 동기화하는지를 이해하는 것",[282,4642,550],{},[282,4644,4645],{},"그리고 이 흐름을 이해하고 나면 JPA를 사용할 때 자주 발생하는 다음과 같은 질문에도 답하기 쉬워진다.",[286,4647,4650],{"className":4648,"code":4649,"language":365,"meta":291},[363],"왜 save()를 호출하지 않아도 UPDATE가 발생하는가?\n\n왜 같은 Entity를 여러 번 조회해도 같은 객체가 반환되는가?\n\n왜 Transaction이 중요한가?\n\n왜 flush()와 commit은 다른가?\n\n왜 clear()가 필요한 경우가 있는가?\n\n왜 준영속 Entity의 변경은 자동으로 반영되지 않는가?\n\n왜 Spring Data JPA를 사용하는데 EntityManager라는 개념이 등장하는가?\n",[293,4651,4649],{"__ignoreMap":291},[282,4653,4654],{},"결국 JPA를 제대로 이해하기 위해서는 Repository API만 보는 것보다 그 아래에서 동작하는:",[286,4656,4659],{"className":4657,"code":4658,"language":365,"meta":291},[363],"EntityManager\n\n+\n\nPersistence Context\n\n+\n\nEntity Lifecycle\n\n+\n\nDirty Checking\n\n+\n\nFlush\n\n+\n\nTransaction\n",[293,4660,4658],{"__ignoreMap":291},[282,4662,2038],{},[282,4664,4665,4667],{},[293,4666,344],{},"는 그 구조를 들여다보기 위한 좋은 출발점이다.",[4669,4670,4671],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":291,"searchDepth":310,"depth":310,"links":4673},[],"2026-09-01","JPA의 @PersistenceContext가 무엇을 의미하는지부터 EntityManager와 영속성 컨텍스트의 관계, 엔티티 생명주기, Dirty Checking, Flush, Transaction과의 관계까지 정리합니다.","md",null,{"tags":4679,"image":4686},[4680,4681,4682,344,334,4540,4683,410,4684,4685],"Java","JPA","Spring Boot","Persistence Context","Flush","Transaction","\u002Fimages\u002FjavaSpring-thumbnail.png",{"icon":20},{"title":4689,"description":4690},"JPA @PersistenceContext 완벽 정리 - EntityManager와 영속성 컨텍스트 이해하기","JPA의 @PersistenceContext 어노테이션이 EntityManager를 어떻게 주입하는지 알아보고, 영속성 컨텍스트의 역할과 엔티티 생명주기, Dirty Checking, Flush, Transaction의 관계를 예제와 함께 정리합니다.","aqkdw-Y5w2FagQsu9pShtfEjAf3laU1d7lDjc5AlOD8",[4693,4695],{"title":22,"path":23,"stem":24,"description":4694,"icon":20,"children":-1},"Java의 record 객체가 등장한 이유와 불변 데이터 객체의 특징, 장단점, DTO 활용법부터 JPA의 @Version을 이용한 낙관적 락과 동시성 제어 원리까지 정리합니다.",{"title":30,"path":31,"stem":32,"description":4696,"icon":20,"children":-1},"Java의 YearMonth를 활용해 연도와 월을 표현하고 특정 월의 시작일과 마지막 날을 계산하는 방법을 정리합니다.",1789947611417]