[{"data":1,"prerenderedAt":1351},["ShallowReactive",2],{"navigation_docs_ko":3,"-ko-project-brobean-brobean-dev-log-15":267,"-ko-project-brobean-brobean-dev-log-15-surround":1346},[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":250,"body":269,"date":1332,"description":1333,"extension":1334,"links":1335,"meta":1336,"navigation":1342,"path":251,"seo":1343,"stem":252,"__hash__":1345},"docs_ko\u002Fko\u002F2.project\u002F2.brobean\u002F915.brobean-dev-log-15.md",{"type":270,"value":271,"toc":1327},"minimark",[272,1323],[273,274,276,281,285,293,362,368,375,386,392,402,406,414,417,466,479,482,599,606,610,615,618,626,632,635,641,644,650,653,659,662,668,675,678,684,687,690,696,710,715,718,727,730,736,740,747,753,797,800,806,809,812,815,842,845,864,867,872,911,914,920,932,936,948,952,955,958,964,967,973,976,979,985,1024,1027,1078,1084,1088,1091,1098,1101,1107,1110,1113,1119,1122,1128,1164,1170,1195,1201,1205,1217,1223,1226,1232,1238,1249,1258,1265,1268,1277,1284,1287,1293,1296,1302,1305,1317],"u-page-card",{":spotlight":275},"true",[277,278,280],"h1",{"id":279},"brobean-프로젝트-15-페이지네이션을-적용하며-page와-slice의-차이를-알게-되다","📖 BroBean 프로젝트 #15 페이지네이션을 적용하며 Page와 Slice의 차이를 알게 되다",[282,283,284],"p",{},"BroBean을 개발하면서 가계부 내역과 알림 내역에도 페이지네이션을 적용하게 되었다.",[282,286,287,288,292],{},"기존에는 페이지네이션이 필요한 경우 대부분 ",[289,290,291],"code",{},"Page\u003CT>","를 사용해서 응답을 내려주고 있었다.",[294,295,300],"pre",{"className":296,"code":297,"language":298,"meta":299,"style":299},"language-java shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Page\u003CTransactionResponse> transactions = transactionRepository.findAll(\n    condition,\n    pageable\n);\n","java","",[289,301,302,341,350,356],{"__ignoreMap":299},[303,304,307,311,315,318,321,325,328,331,334,338],"span",{"class":305,"line":306},"line",1,[303,308,310],{"class":309},"spNyl","Page",[303,312,314],{"class":313},"sMK4o","\u003C",[303,316,317],{"class":309},"TransactionResponse",[303,319,320],{"class":313},">",[303,322,324],{"class":323},"sTEyZ"," transactions ",[303,326,327],{"class":313},"=",[303,329,330],{"class":323}," transactionRepository",[303,332,333],{"class":313},".",[303,335,337],{"class":336},"s2Zo4","findAll",[303,339,340],{"class":313},"(\n",[303,342,344,347],{"class":305,"line":343},2,[303,345,346],{"class":323},"    condition",[303,348,349],{"class":313},",\n",[303,351,353],{"class":305,"line":352},3,[303,354,355],{"class":323},"    pageable\n",[303,357,359],{"class":305,"line":358},4,[303,360,361],{"class":313},");\n",[282,363,364,365,367],{},"페이지 번호나 전체 데이터 개수를 같이 내려줘야 하는 경우에는 ",[289,366,310],{},"가 자연스럽게 느껴졌기 때문에 별다른 고민 없이 사용하고 있었다.",[282,369,370,371,374],{},"그런데 이번에 알림 내역의 페이지네이션을 구현하면서 ",[289,372,373],{},"Slice\u003CT>","라는 객체를 알게 되었다.",[282,376,377,378,380,381,385],{},"처음에는 단순히 ",[289,379,310],{},"와 비슷한 또 하나의 페이지네이션 객체라고 생각했는데, 실제로 살펴보니 ",[382,383,384],"strong",{},"전체 데이터 개수를 조회하느냐의 차이","가 있었고, 이 차이가 생각보다 꽤 중요한 부분이었다.",[282,387,388,389,391],{},"특히 어떤 화면에서는 전체 데이터 개수가 필요하지만, 어떤 화면에서는 단순히 \"다음 데이터가 있는가?\"만 알면 되기 때문에 무조건 ",[289,390,310],{},"를 사용할 필요가 없었다.",[282,393,394,395,397,398,401],{},"이번 작업에서는 ",[289,396,310],{},"와 ",[289,399,400],{},"Slice","의 차이를 정리하고, BroBean에서는 각각 어떤 상황에 적용했는지 기록해보려고 한다.",[277,403,405],{"id":404},"page와-slice","Page와 Slice",[282,407,408,409,397,411,413],{},"Spring Data에서 제공하는 ",[289,410,310],{},[289,412,400],{},"는 모두 페이지 단위로 데이터를 조회하기 위한 객체다.",[282,415,416],{},"둘의 관계를 먼저 보면 다음과 같다.",[294,418,420],{"className":296,"code":419,"language":298,"meta":299,"style":299},"public interface Page\u003CT> extends Slice\u003CT> {\n    ...\n}\n",[289,421,422,456,461],{"__ignoreMap":299},[303,423,424,427,430,434,436,439,441,444,447,449,451,453],{"class":305,"line":306},[303,425,426],{"class":309},"public",[303,428,429],{"class":309}," interface",[303,431,433],{"class":432},"sBMFI"," Page",[303,435,314],{"class":313},[303,437,438],{"class":309},"T",[303,440,320],{"class":313},[303,442,443],{"class":309}," extends",[303,445,446],{"class":432}," Slice",[303,448,314],{"class":313},[303,450,438],{"class":309},[303,452,320],{"class":313},[303,454,455],{"class":313}," {\n",[303,457,458],{"class":305,"line":343},[303,459,460],{"class":313},"    ...\n",[303,462,463],{"class":305,"line":352},[303,464,465],{"class":313},"}\n",[282,467,468,469,471,472,474,475,478],{},"즉, ",[289,470,310],{},"는 ",[289,473,400],{},"의 기능을 포함하면서 ",[382,476,477],{},"전체 데이터 개수와 전체 페이지 수에 대한 정보가 추가된 형태","라고 볼 수 있다.",[282,480,481],{},"간단하게 비교하면 다음과 같다.",[483,484,485,499],"table",{},[486,487,488],"thead",{},[489,490,491,495,497],"tr",{},[492,493,494],"th",{},"구분",[492,496,310],{},[492,498,400],{},[500,501,502,513,522,531,540,549,558,568,577,588],"tbody",{},[489,503,504,508,511],{},[505,506,507],"td",{},"현재 페이지 데이터",[505,509,510],{},"O",[505,512,510],{},[489,514,515,518,520],{},[505,516,517],{},"현재 페이지 번호",[505,519,510],{},[505,521,510],{},[489,523,524,527,529],{},[505,525,526],{},"페이지 크기",[505,528,510],{},[505,530,510],{},[489,532,533,536,538],{},[505,534,535],{},"현재 조회된 데이터 개수",[505,537,510],{},[505,539,510],{},[489,541,542,545,547],{},[505,543,544],{},"다음 페이지 존재 여부",[505,546,510],{},[505,548,510],{},[489,550,551,554,556],{},[505,552,553],{},"이전 페이지 존재 여부",[505,555,510],{},[505,557,510],{},[489,559,560,563,565],{},[505,561,562],{},"전체 데이터 개수",[505,564,510],{},[505,566,567],{},"X",[489,569,570,573,575],{},[505,571,572],{},"전체 페이지 수",[505,574,510],{},[505,576,567],{},[489,578,579,582,585],{},[505,580,581],{},"전체 Count 조회",[505,583,584],{},"일반적으로 필요할 수 있음",[505,586,587],{},"필요 없음",[489,589,590,593,596],{},[505,591,592],{},"주요 용도",[505,594,595],{},"페이지 번호 기반 UI",[505,597,598],{},"더보기 \u002F 무한 스크롤",[282,600,601,602,605],{},"결국 가장 큰 차이는 ",[382,603,604],{},"전체 데이터 개수를 알고 있느냐","이다.",[607,608,310],"h2",{"id":609},"page",[282,611,612,614],{},[289,613,310],{},"는 현재 페이지뿐만 아니라 전체 데이터에 대한 정보까지 제공한다.",[282,616,617],{},"예를 들어 데이터가 총 153개이고 한 페이지에 10개씩 보여준다면 다음과 같은 정보를 얻을 수 있다.",[294,619,624],{"className":620,"code":622,"language":623,"meta":299},[621],"language-text","현재 페이지: 3\n페이지 크기: 10\n현재 페이지 데이터: 10개\n\n전체 데이터: 153개\n전체 페이지: 16개\n다음 페이지 존재: true\n","text",[289,625,622],{"__ignoreMap":299},[282,627,628,629,631],{},"이런 정보가 필요한 화면이라면 ",[289,630,310],{},"가 적절하다.",[282,633,634],{},"특히 프론트에서 다음과 같은 UI를 만들어야 한다면 전체 데이터 개수와 전체 페이지 수가 필요하다.",[294,636,639],{"className":637,"code":638,"language":623,"meta":299},[621],"\u003C 1 2 3 4 5 ... 16 >\n",[289,640,638],{"__ignoreMap":299},[282,642,643],{},"또는",[294,645,648],{"className":646,"code":647,"language":623,"meta":299},[621],"전체 가계부 내역 153개\n",[289,649,647],{"__ignoreMap":299},[282,651,652],{},"이 경우에는 단순히 현재 페이지의 데이터만 가져오는 것으로는 충분하지 않다.",[282,654,655,656,658],{},"전체 데이터 개수를 알아야 하기 때문에 Count 조회가 필요하고, ",[289,657,310],{},"가 이런 정보를 제공하기에 적합하다.",[277,660,400],{"id":661},"slice",[282,663,664,665,667],{},"반면 ",[289,666,400],{},"는 전체 데이터 개수에는 관심이 없다.",[282,669,670,671,674],{},"현재 조회한 데이터와 함께 ",[382,672,673],{},"다음 데이터가 존재하는지만 확인","한다.",[282,676,677],{},"예를 들어 한 번에 10개의 데이터를 보여준다고 해보자.",[294,679,682],{"className":680,"code":681,"language":623,"meta":299},[621],"1페이지\n→ 데이터 10개\n→ 다음 데이터 있음\n\n2페이지\n→ 데이터 10개\n→ 다음 데이터 있음\n\n3페이지\n→ 데이터 10개\n→ 다음 데이터 없음\n",[289,683,681],{"__ignoreMap":299},[282,685,686],{},"이 경우 굳이 전체 데이터가 몇 개인지 알 필요가 없다.",[282,688,689],{},"프론트에서는 다음과 같이 처리할 수 있다.",[294,691,694],{"className":692,"code":693,"language":623,"meta":299},[621],"알림 10개\n[더보기]\n",[289,695,693],{"__ignoreMap":299},[282,697,698,699,702,703,705,706,709],{},"그리고 ",[289,700,701],{},"hasNext()","가 ",[289,704,275],{},"라면 더보기 버튼을 보여주고, ",[289,707,708],{},"false","라면 더 이상 데이터를 불러오지 않으면 된다.",[282,711,712,714],{},[289,713,400],{},"는 전체 Count를 계산하지 않고 다음 데이터가 존재하는지만 판단하기 때문에 이런 형태의 UI에 적합하다.",[282,716,717],{},"Spring Data에서는 이를 판단하기 위해 실제 페이지 크기보다 하나 더 조회하는 방식으로 다음 데이터의 존재 여부를 확인할 수 있다.",[282,719,720,721,723,724,726],{},"예를 들어 페이지 크기가 10이라면 내부적으로 11개를 조회해서 11번째 데이터가 존재하는지 확인하고, 존재한다면 ",[289,722,701],{},"를 ",[289,725,275],{},"로 판단하는 방식이다.",[282,728,729],{},"따라서 개념적으로는 다음과 같이 생각할 수 있다.",[294,731,734],{"className":732,"code":733,"language":623,"meta":299},[621],"Page\n→ \"전체 데이터가 몇 개이고, 전체 페이지가 몇 개인가?\"\n\nSlice\n→ \"현재 데이터 다음에 더 있는가?\"\n",[289,735,733],{"__ignoreMap":299},[277,737,739],{"id":738},"page를-사용하면-count-쿼리가-필요한-이유","Page를 사용하면 Count 쿼리가 필요한 이유",[282,741,742,397,744,746],{},[289,743,310],{},[289,745,400],{},"의 차이를 알아보면서 가장 관심이 갔던 부분은 Count 쿼리였다.",[282,748,749,750,752],{},"예를 들어 다음과 같이 ",[289,751,310],{},"를 사용한다고 해보자.",[294,754,756],{"className":296,"code":755,"language":298,"meta":299,"style":299},"Page\u003CTransactionResponse> result =\n    transactionRepository.findAll(condition, pageable);\n",[289,757,758,774],{"__ignoreMap":299},[303,759,760,762,764,766,768,771],{"class":305,"line":306},[303,761,310],{"class":309},[303,763,314],{"class":313},[303,765,317],{"class":309},[303,767,320],{"class":313},[303,769,770],{"class":323}," result ",[303,772,773],{"class":313},"=\n",[303,775,776,779,781,783,786,789,792,795],{"class":305,"line":343},[303,777,778],{"class":323},"    transactionRepository",[303,780,333],{"class":313},[303,782,337],{"class":336},[303,784,785],{"class":313},"(",[303,787,788],{"class":323},"condition",[303,790,791],{"class":313},",",[303,793,794],{"class":323}," pageable",[303,796,361],{"class":313},[282,798,799],{},"가계부 데이터가 다음과 같이 존재한다고 하면,",[294,801,804],{"className":802,"code":803,"language":623,"meta":299},[621],"전체 데이터\n153건\n\n현재 페이지\n3페이지\n\n페이지 크기\n10\n",[289,805,803],{"__ignoreMap":299},[282,807,808],{},"현재 페이지의 데이터를 조회하는 것만으로는 전체 데이터가 153건이라는 사실을 알 수 없다.",[282,810,811],{},"그래서 일반적으로 데이터 조회와 별개로 전체 개수를 확인하기 위한 Count 쿼리가 필요하다.",[282,813,814],{},"개념적으로 보면 다음과 같은 두 가지 작업이 이루어질 수 있다.",[294,816,820],{"className":817,"code":818,"language":819,"meta":299,"style":299},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","SELECT ...\nFROM transaction\nWHERE ...\nLIMIT 10 OFFSET 20;\n","sql",[289,821,822,827,832,837],{"__ignoreMap":299},[303,823,824],{"class":305,"line":306},[303,825,826],{},"SELECT ...\n",[303,828,829],{"class":305,"line":343},[303,830,831],{},"FROM transaction\n",[303,833,834],{"class":305,"line":352},[303,835,836],{},"WHERE ...\n",[303,838,839],{"class":305,"line":358},[303,840,841],{},"LIMIT 10 OFFSET 20;\n",[282,843,844],{},"그리고",[294,846,848],{"className":817,"code":847,"language":819,"meta":299,"style":299},"SELECT COUNT(*)\nFROM transaction\nWHERE ...;\n",[289,849,850,855,859],{"__ignoreMap":299},[303,851,852],{"class":305,"line":306},[303,853,854],{},"SELECT COUNT(*)\n",[303,856,857],{"class":305,"line":343},[303,858,831],{},[303,860,861],{"class":305,"line":352},[303,862,863],{},"WHERE ...;\n",[282,865,866],{},"첫 번째 쿼리는 실제 데이터를 가져오기 위한 것이고, 두 번째 쿼리는 전체 페이지 수를 계산하기 위한 것이다.",[282,868,664,869,871],{},[289,870,400],{},"는 전체 데이터 개수가 필요하지 않기 때문에 Count 쿼리를 수행할 필요가 없다.",[294,873,875],{"className":296,"code":874,"language":298,"meta":299,"style":299},"Slice\u003CNotificationResponse> result =\n    notificationRepository.findAll(condition, pageable);\n",[289,876,877,892],{"__ignoreMap":299},[303,878,879,881,883,886,888,890],{"class":305,"line":306},[303,880,400],{"class":309},[303,882,314],{"class":313},[303,884,885],{"class":309},"NotificationResponse",[303,887,320],{"class":313},[303,889,770],{"class":323},[303,891,773],{"class":313},[303,893,894,897,899,901,903,905,907,909],{"class":305,"line":343},[303,895,896],{"class":323},"    notificationRepository",[303,898,333],{"class":313},[303,900,337],{"class":336},[303,902,785],{"class":313},[303,904,788],{"class":323},[303,906,791],{"class":313},[303,908,794],{"class":323},[303,910,361],{"class":313},[282,912,913],{},"결과적으로 데이터 조회에 필요한 쿼리만 수행하면 된다.",[282,915,916,917,919],{},"물론 실제 Spring Data의 내부 동작에서는 조회 결과나 쿼리 형태에 따라 Count 실행을 최적화하는 경우도 있기 때문에 ",[289,918,310],{},"를 사용한다고 항상 무조건 Count 쿼리가 실행된다고 단정할 수는 없다.",[282,921,922,923,931],{},"다만 기본적인 차이는 ",[382,924,925,927,928,930],{},[289,926,310],{},"는 전체 개수 계산을 위한 Count 정보가 필요하고, ",[289,929,400],{},"는 필요하지 않다","는 것이다.",[277,933,935],{"id":934},"brobean에서는-어떻게-적용했을까","BroBean에서는 어떻게 적용했을까?",[282,937,938,939,947],{},"이번 페이지네이션 작업에서는 모든 화면에 같은 객체를 사용하는 것보다 ",[382,940,941,942,397,944,946],{},"화면에서 어떤 정보가 필요한지를 기준으로 ",[289,943,310],{},[289,945,400],{},"를 나누는 것","에 초점을 맞췄다.",[607,949,951],{"id":950},"가계부-내역은-page","가계부 내역은 Page",[282,953,954],{},"가계부 내역은 전체 데이터 개수와 전체 페이지 정보가 필요한 화면이었다.",[282,956,957],{},"예를 들어 사용자가 자신의 가계부를 확인할 때,",[294,959,962],{"className":960,"code":961,"language":623,"meta":299},[621],"가계부 내역 127건\n",[289,963,961],{"__ignoreMap":299},[282,965,966],{},"과 같은 전체 데이터 개수를 보여줄 수 있고,",[294,968,971],{"className":969,"code":970,"language":623,"meta":299},[621],"\u003C 1 2 3 4 5 ... >\n",[289,972,970],{"__ignoreMap":299},[282,974,975],{},"형태의 페이지 네비게이션을 제공할 수도 있다.",[282,977,978],{},"이 경우에는 현재 페이지의 데이터만 알아서는 부족하다.",[282,980,981,982,984],{},"전체 데이터 개수와 전체 페이지 수가 필요하기 때문에 ",[289,983,310],{},"를 사용하는 것이 자연스럽다.",[294,986,988],{"className":296,"code":987,"language":298,"meta":299,"style":299},"Page\u003CLedgerResponse> result =\n    ledgerRepository.findAll(condition, pageable);\n",[289,989,990,1005],{"__ignoreMap":299},[303,991,992,994,996,999,1001,1003],{"class":305,"line":306},[303,993,310],{"class":309},[303,995,314],{"class":313},[303,997,998],{"class":309},"LedgerResponse",[303,1000,320],{"class":313},[303,1002,770],{"class":323},[303,1004,773],{"class":313},[303,1006,1007,1010,1012,1014,1016,1018,1020,1022],{"class":305,"line":343},[303,1008,1009],{"class":323},"    ledgerRepository",[303,1011,333],{"class":313},[303,1013,337],{"class":336},[303,1015,785],{"class":313},[303,1017,788],{"class":323},[303,1019,791],{"class":313},[303,1021,794],{"class":323},[303,1023,361],{"class":313},[282,1025,1026],{},"응답에서도 필요한 정보를 사용할 수 있다.",[294,1028,1030],{"className":296,"code":1029,"language":298,"meta":299,"style":299},"result.getContent();\nresult.getTotalElements();\nresult.getTotalPages();\nresult.hasNext();\n",[289,1031,1032,1045,1056,1067],{"__ignoreMap":299},[303,1033,1034,1037,1039,1042],{"class":305,"line":306},[303,1035,1036],{"class":323},"result",[303,1038,333],{"class":313},[303,1040,1041],{"class":336},"getContent",[303,1043,1044],{"class":313},"();\n",[303,1046,1047,1049,1051,1054],{"class":305,"line":343},[303,1048,1036],{"class":323},[303,1050,333],{"class":313},[303,1052,1053],{"class":336},"getTotalElements",[303,1055,1044],{"class":313},[303,1057,1058,1060,1062,1065],{"class":305,"line":352},[303,1059,1036],{"class":323},[303,1061,333],{"class":313},[303,1063,1064],{"class":336},"getTotalPages",[303,1066,1044],{"class":313},[303,1068,1069,1071,1073,1076],{"class":305,"line":358},[303,1070,1036],{"class":323},[303,1072,333],{"class":313},[303,1074,1075],{"class":336},"hasNext",[303,1077,1044],{"class":313},[282,1079,1080,1081,1083],{},"특히 가계부처럼 데이터의 규모를 사용자에게 보여주거나 페이지 번호를 직접 이동하는 UI라면 ",[289,1082,310],{},"가 적합하다.",[607,1085,1087],{"id":1086},"알림-내역은-slice","알림 내역은 Slice",[282,1089,1090],{},"반면 알림 내역은 조금 달랐다.",[282,1092,1093,1094,1097],{},"알림 화면에서 사용자에게 필요한 정보는 전체 알림이 몇 개인지보다는 ",[382,1095,1096],{},"다음 알림이 더 있는지 여부","였다.",[282,1099,1100],{},"예를 들어 이미 확인한 알림이 300개 있다고 해서,",[294,1102,1105],{"className":1103,"code":1104,"language":623,"meta":299},[621],"전체 알림 300개\n",[289,1106,1104],{"__ignoreMap":299},[282,1108,1109],{},"라는 정보를 반드시 사용자에게 보여줄 필요는 없었다.",[282,1111,1112],{},"알림 목록을 20개씩 조회하고 다음 알림이 존재한다면 계속 불러오면 된다.",[294,1114,1117],{"className":1115,"code":1116,"language":623,"meta":299},[621],"알림 20개\n↓\n더보기\n\n알림 20개 추가\n↓\n더보기\n\n더 이상 없음\n",[289,1118,1116],{"__ignoreMap":299},[282,1120,1121],{},"이런 경우에는 전체 Count를 계산할 이유가 크지 않다.",[282,1123,1124,1125,1127],{},"그래서 알림 내역에는 ",[289,1126,400],{},"를 적용했다.",[294,1129,1130],{"className":296,"code":874,"language":298,"meta":299,"style":299},[289,1131,1132,1146],{"__ignoreMap":299},[303,1133,1134,1136,1138,1140,1142,1144],{"class":305,"line":306},[303,1135,400],{"class":309},[303,1137,314],{"class":313},[303,1139,885],{"class":309},[303,1141,320],{"class":313},[303,1143,770],{"class":323},[303,1145,773],{"class":313},[303,1147,1148,1150,1152,1154,1156,1158,1160,1162],{"class":305,"line":343},[303,1149,896],{"class":323},[303,1151,333],{"class":313},[303,1153,337],{"class":336},[303,1155,785],{"class":313},[303,1157,788],{"class":323},[303,1159,791],{"class":313},[303,1161,794],{"class":323},[303,1163,361],{"class":313},[282,1165,1166,1167,1169],{},"그리고 프론트에서는 ",[289,1168,701],{},"만 확인하면 된다.",[294,1171,1173],{"className":296,"code":1172,"language":298,"meta":299,"style":299},"result.getContent();\nresult.hasNext();\n",[289,1174,1175,1185],{"__ignoreMap":299},[303,1176,1177,1179,1181,1183],{"class":305,"line":306},[303,1178,1036],{"class":323},[303,1180,333],{"class":313},[303,1182,1041],{"class":336},[303,1184,1044],{"class":313},[303,1186,1187,1189,1191,1193],{"class":305,"line":343},[303,1188,1036],{"class":323},[303,1190,333],{"class":313},[303,1192,1075],{"class":336},[303,1194,1044],{"class":313},[282,1196,1197,1198],{},"전체 알림이 300개인지 3,000개인지는 중요하지 않고, ",[382,1199,1200],{},"현재 조회한 알림 이후에 더 가져올 데이터가 있는지만 알면 되기 때문이다.",[277,1202,1204],{"id":1203},"결국-중요한-것은-페이지네이션-방식의-선택","결국 중요한 것은 페이지네이션 방식의 선택",[282,1206,1207,1208,397,1210,1212,1213,1216],{},"이번 작업을 하면서 ",[289,1209,310],{},[289,1211,400],{},"의 차이를 알게 된 것보다 더 중요했던 부분은 ",[382,1214,1215],{},"페이지네이션 객체를 화면의 요구사항에 맞춰 선택해야 한다는 점","이었다.",[282,1218,1219,1220,1222],{},"기존에는 페이지네이션이 필요하면 자연스럽게 ",[289,1221,310],{},"를 사용했다.",[282,1224,1225],{},"하지만 실제로 필요한 정보가 무엇인지 생각해보면 두 화면의 요구사항은 달랐다.",[294,1227,1230],{"className":1228,"code":1229,"language":623,"meta":299},[621],"가계부\n\n현재 데이터\n+ 전체 데이터 개수\n+ 전체 페이지 수\n+ 다음 페이지 여부\n\n→ Page\n",[289,1231,1229],{"__ignoreMap":299},[294,1233,1236],{"className":1234,"code":1235,"language":623,"meta":299},[621],"알림\n\n현재 데이터\n+ 다음 데이터 존재 여부\n\n→ Slice\n",[289,1237,1235],{"__ignoreMap":299},[282,1239,1240,1241,702,1243,1245,1246,1248],{},"결국 ",[289,1242,310],{},[289,1244,400],{},"보다 무조건 좋은 것도 아니고, 반대로 ",[289,1247,400],{},"가 항상 더 좋은 것도 아니다.",[282,1250,1251,1252,1254,1255,1257],{},"전체 데이터 개수가 필요한 경우에는 ",[289,1253,310],{},"가 필요하고, 단순히 데이터를 이어서 가져오는 형태라면 ",[289,1256,400],{},"만으로 충분하다.",[282,1259,1260,1261,1264],{},"특히 데이터가 많아질수록 전체 Count를 계산하는 비용도 고려할 필요가 있기 때문에, ",[382,1262,1263],{},"실제로 전체 개수가 필요한 화면인지 먼저 확인하고 페이지네이션 방식을 결정하는 것","이 중요하다는 것을 알게 되었다.",[277,1266,1267],{"id":1267},"마무리",[282,1269,1270,1271,1273,1274,1276],{},"이번 작업 전까지는 페이지네이션을 구현하면서 ",[289,1272,310],{},"를 주로 사용했고 ",[289,1275,400],{},"라는 선택지가 있다는 것도 크게 신경 쓰지 않았었다.",[282,1278,1279,1280,1283],{},"하지만 이번에 알림 내역을 구현하면서 둘의 차이를 살펴보니 단순히 이름만 다른 객체가 아니라, ",[382,1281,1282],{},"전체 데이터 개수를 조회해야 하는지에 따라 데이터 조회 방식과 API가 제공하는 정보 자체가 달라지는 구조","라는 것을 알게 되었다.",[282,1285,1286],{},"정리하면 다음과 같다.",[294,1288,1291],{"className":1289,"code":1290,"language":623,"meta":299},[621],"Page\n→ 전체 데이터 개수가 필요하다.\n→ 전체 페이지 수가 필요하다.\n→ 페이지 번호 기반 UI에 적합하다.\n→ Count 조회가 필요할 수 있다.\n\nSlice\n→ 전체 데이터 개수는 필요하지 않다.\n→ 다음 데이터가 존재하는지만 알면 된다.\n→ 더보기 \u002F 무한 스크롤 등에 적합하다.\n→ 전체 Count 조회 없이 페이지네이션을 구성할 수 있다.\n",[289,1292,1290],{"__ignoreMap":299},[282,1294,1295],{},"BroBean에서는 이 기준에 따라",[294,1297,1300],{"className":1298,"code":1299,"language":623,"meta":299},[621],"가계부 내역 → Page\n알림 내역   → Slice\n",[289,1301,1299],{"__ignoreMap":299},[282,1303,1304],{},"로 나누어 적용했다.",[282,1306,1307,1308,1316],{},"페이지네이션은 단순히 데이터를 몇 개씩 잘라서 가져오는 기능이라고 생각했는데, 이번 작업을 통해 ",[382,1309,1310,1311,397,1313,1315],{},"어떤 페이지네이션 정보를 API에서 제공해야 하는지까지 고려해서 ",[289,1312,310],{},[289,1314,400],{},"를 선택해야 한다는 것","을 알게 되었다.",[282,1318,1319,1320,1322],{},"작은 차이처럼 보이지만 데이터 조회 비용과 API 응답의 의미까지 연결되는 부분이라, 앞으로 페이지네이션을 구현할 때는 무조건 ",[289,1321,310],{},"부터 사용하는 것보다는 해당 화면에서 정말 전체 Count가 필요한지를 먼저 확인해볼 것 같다.",[1324,1325,1326],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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}",{"title":299,"searchDepth":343,"depth":343,"links":1328},[1329,1330,1331],{"id":609,"depth":343,"text":310},{"id":950,"depth":343,"text":951},{"id":1086,"depth":343,"text":1087},"2026-09-18","BroBean 프로젝트에서 페이지네이션을 적용하며 Spring Data JPA의 Page와 Slice 차이를 알아보고, 가계부와 알림 내역에 각각 다른 방식을 적용한 경험을 정리한다.","md",null,{"tags":1337,"image":1341},[1338,11,1339,1340,310,400],"BroBean","Spring Data JPA","Pagination","\u002Fimages\u002Fbrobean\u002Fog-image.png",{"icon":20},{"title":250,"description":1344},"Spring Data JPA의 Page와 Slice 차이와 BroBean 프로젝트에서 페이지네이션을 적용한 과정을 정리한다.","wlxYyxgSWh0CAf98RfSE9pbm-c0rAXojuBEX12_NoVc",[1347,1349],{"title":246,"path":247,"stem":248,"description":1348,"icon":20,"children":-1},"BroBean 커플 기능을 구현하던 중 AuthService와 CoupleService 사이에서 발생한 순환 참조 문제와 ObjectProvider를 활용해 의존성 주입 시점을 지연시키는 방법을 정리합니다.",{"title":264,"path":265,"stem":266,"description":1350,"icon":20,"children":-1},"제한된 네트워크 환경에서 발생한 Nuxt Icon 모듈 오류 원인을 분석하고 Custom Collection을 활용해 로컬 아이콘 환경을 구성한 과정 정리",1789947611365]