[{"data":1,"prerenderedAt":1698},["ShallowReactive",2],{"post-document:\u002Fbackend\u002Fspring\u002F2026\u002F08\u002F18\u002F강의교재_정리\u002F":3},{"id":4,"title":5,"body":6,"categories":1683,"date":1686,"description":91,"extension":1687,"image":1688,"key_concepts":1688,"last_modified_at":1688,"legacyPath":1689,"meta":1690,"navigation":1692,"part":1688,"path":1693,"published":1692,"robots":1688,"seo":1694,"series":1688,"stem":1695,"strengths":1688,"summary":1688,"tags":1696,"tradeoffs":1688,"__hash__":1697},"posts\u002Fposts\u002FBackend\u002FSPRING\u002F강의교재_정리.md","전체 데이터 구조",{"type":7,"value":8,"toc":1670},"minimark",[9,13,79,83,88,92,161,164,167,170,173,235,239,309,312,315,325,329,332,335,412,415,485,489,492,542,546,610,614,617,623,659,662,771,775,867,870,884,887,890,894,897,900,969,973,1097,1101,1215,1219,1222,1225,1321,1325,1401,1404,1431,1434,1506,1510,1518,1521,1526,1529,1534,1539,1542,1553,1558,1561,1564,1567,1570,1573,1576,1579,1582,1585,1588,1591,1594,1597,1600,1603,1606,1609,1612,1615,1618,1621,1624,1627,1630,1633,1636,1639,1642,1645,1648,1651,1654,1657,1660,1663,1666],[10,11,5],"h1",{"id":12},"전체-데이터-구조",[14,15,20],"pre",{"className":16,"code":17,"language":18,"meta":19,"style":19},"language-mermaid shiki shiki-themes github-light github-dark","flowchart LR\n  A[\"REST API 설계\"] --> B[\"Spring Boot\"]\n  B --> C[\"Spring MVC 요청 처리\"]\n  C --> D[\"Controller → Service → Repository\"]\n  D --> E[\"IoC Container와 DI\"]\n  E --> F[\"Proxy 기반 기능\"]\n  F --> G[\"AOP, Validation, Async, Transaction\"]\n  D --> H[\"JPA와 DB\"]\n  H --> I[\"API 문서화와 운영 모니터링\"]\n","mermaid","",[21,22,23,31,37,43,49,55,61,67,73],"code",{"__ignoreMap":19},[24,25,28],"span",{"class":26,"line":27},"line",1,[24,29,30],{},"flowchart LR\n",[24,32,34],{"class":26,"line":33},2,[24,35,36],{},"  A[\"REST API 설계\"] --> B[\"Spring Boot\"]\n",[24,38,40],{"class":26,"line":39},3,[24,41,42],{},"  B --> C[\"Spring MVC 요청 처리\"]\n",[24,44,46],{"class":26,"line":45},4,[24,47,48],{},"  C --> D[\"Controller → Service → Repository\"]\n",[24,50,52],{"class":26,"line":51},5,[24,53,54],{},"  D --> E[\"IoC Container와 DI\"]\n",[24,56,58],{"class":26,"line":57},6,[24,59,60],{},"  E --> F[\"Proxy 기반 기능\"]\n",[24,62,64],{"class":26,"line":63},7,[24,65,66],{},"  F --> G[\"AOP, Validation, Async, Transaction\"]\n",[24,68,70],{"class":26,"line":69},8,[24,71,72],{},"  D --> H[\"JPA와 DB\"]\n",[24,74,76],{"class":26,"line":75},9,[24,77,78],{},"  H --> I[\"API 문서화와 운영 모니터링\"]\n",[10,80,82],{"id":81},"_1-핵심-개녕-정리","1. 핵심 개녕 정리",[84,85,87],"h2",{"id":86},"a-rest-api","A. REST API",[89,90,91],"p",{},"REST는 \"웹의 자원(RESORECE)\" 을 URI 로 식별하고, HTTP Method로 조작하고, JSON 형태로 주고 받는 방ㅅ기",[93,94,95,111],"table",{},[96,97,98],"thead",{},[99,100,101,105,108],"tr",{},[102,103,104],"th",{},"요소",[102,106,107],{},"역할",[102,109,110],{},"예시",[112,113,114,126,139,150],"tbody",{},[99,115,116,120,123],{},[117,118,119],"td",{},"Resource",[117,121,122],{},"서버가 제공하는 대상, 명사로 표현",[117,124,125],{},"User, Product, Order",[99,127,128,131,134],{},[117,129,130],{},"URI",[117,132,133],{},"자원이 무엇인지 식별",[117,135,136],{},[21,137,138],{},"\u002Fusers\u002F10",[99,140,141,144,147],{},[117,142,143],{},"HTTP Method",[117,145,146],{},"자원에 할 행동 표현",[117,148,149],{},"GET, POST, PUT, PATCH, DELETE",[99,151,152,155,158],{},[117,153,154],{},"Representation",[117,156,157],{},"자원을 전달하는 데이터 형식",[117,159,160],{},"JSON, XML, 파일",[89,162,163],{},"GET \u002Fusers\u002F10\n→ “10번 사용자를 조회한다”",[89,165,166],{},"POST \u002Fusers\n→ “사용자 컬렉션에 새 사용자를 생성한다”",[89,168,169],{},"REST 설계의 핵심은 URI에 동사를 넣지 않는 것.",[89,171,172],{},"좋음 : GET\u002Fusers\u002F10\n나쁨 : GET\u002FgetUser?id=10",[93,174,175,185],{},[96,176,177],{},[99,178,179,182],{},[102,180,181],{},"REST 원칙",[102,183,184],{},"뜻",[112,186,187,195,203,211,219,227],{},[99,188,189,192],{},[117,190,191],{},"Client-Server",[117,193,194],{},"화면 역할과 서버의 데이터·비즈니스 역할을 분리",[99,196,197,200],{},[117,198,199],{},"Stateless",[117,201,202],{},"서버가 이전 요청의 상태를 기억하지 않고, 각 요청이 필요한 정보를 포함",[99,204,205,208],{},[117,206,207],{},"Cacheable",[117,209,210],{},"응답의 재사용 가능 여부를 HTTP 캐시로 표현",[99,212,213,216],{},[117,214,215],{},"Uniform Interface",[117,217,218],{},"URI, Method, 상태 코드, JSON 형식을 일관되게 사용",[99,220,221,224],{},[117,222,223],{},"Layered System",[117,225,226],{},"Gateway, 인증 서버, 로드밸런서 등이 중간에 있어도 클라이언트는 몰라도 됨",[99,228,229,232],{},[117,230,231],{},"Code on Demand",[117,233,234],{},"서버가 JavaScript 같은 실행 코드를 내려줄 수 있음, 선택 사항",[84,236,238],{"id":237},"b-spring과-spring-boot","B. Spring과 Spring Boot",[93,240,241,251],{},[96,242,243],{},[99,244,245,248],{},[102,246,247],{},"용어",[102,249,250],{},"정의",[112,252,253,261,269,277,285,293,301],{},[99,254,255,258],{},[117,256,257],{},"Spring",[117,259,260],{},"Java 객체의 생성, 연결, 공통 기능 처리를 도와주는 프레임워크",[99,262,263,266],{},[117,264,265],{},"Spring Boot",[117,267,268],{},"Spring 설정을 자동화하고 내장 서버로 빠르게 실행하게 만든 플랫폼",[99,270,271,274],{},[117,272,273],{},"Starter",[117,275,276],{},"목적별 의존성을 묶어 제공하는 라이브러리 묶음",[99,278,279,282],{},[117,280,281],{},"Auto Configuration",[117,283,284],{},"추가된 라이브러리와 설정을 보고 필요한 Bean을 자동 설정하는 기능",[99,286,287,290],{},[117,288,289],{},"Embedded Server",[117,291,292],{},"Tomcat 같은 서버를 애플리케이션 내부에 포함해 JAR만으로 실행하는 방식",[99,294,295,298],{},[117,296,297],{},"Bean",[117,299,300],{},"Spring IoC Container가 생성하고 관리하는 객체",[99,302,303,306],{},[117,304,305],{},"Component Scan",[117,307,308],{},"특정 패키지 아래에서 Bean 후보 클래스를 찾아 자동 등록하는 기능",[89,310,311],{},"예시로 @SpringBootApplication은 아래 기능을 묶는다.",[89,313,314],{},"@SpringBootApplication\n= @Configuration",[316,317,318,322],"ul",{},[319,320,321],"li",{},"@EnableAutoConfiguration",[319,323,324],{},"@ComponentScan",[84,326,328],{"id":327},"c-spring-mvc와-controller","C. Spring MVC와 Controller",[89,330,331],{},"Spring MVC는 DispatcherServlet은 모든 HTTP 요청의 첫 관문인 Front Controller",[89,333,334],{},"클라이언트\n-> Tomcat이 HTTP 요청 수신\n-> DispatchServlet\n-> HandlerMapping이 URL에 맞는 Controller 메서드 탐색\n-> HandlerAdapter가 Controller 메서드 호출\n-> Controller -> Service -> Repository\n-> HTTPMessageConverter가 Java 객체를 JSON으로 변환\n-> 응답 전송",[93,336,337,345],{},[96,338,339],{},[99,340,341,343],{},[102,342,247],{},[102,344,250],{},[112,346,347,355,363,371,379,389,402],{},[99,348,349,352],{},[117,350,351],{},"DispatcherServlet",[117,353,354],{},"모든 요청을 받아 적절한 Controller 처리로 연결하는 Front Controller",[99,356,357,360],{},[117,358,359],{},"HandlerMapping",[117,361,362],{},"URL과 HTTP Method에 맞는 Controller 메서드를 찾는 역할",[99,364,365,368],{},[117,366,367],{},"HandlerAdapter",[117,369,370],{},"찾은 Controller 메서드를 실제로 호출하는 역할",[99,372,373,376],{},[117,374,375],{},"HTTPMessageConverter",[117,377,378],{},"JSON 요청 본문을 Java 객체로, Java 반환 객체를 JSON으로 변환",[99,380,381,386],{},[117,382,383],{},[21,384,385],{},"@Controller",[117,387,388],{},"주로 View 이름을 반환하는 MVC Controller",[99,390,391,396],{},[117,392,393],{},[21,394,395],{},"@RestController",[117,397,398,401],{},[21,399,400],{},"@Controller + @ResponseBody",", 반환값을 HTTP Body로 보내는 REST Controller",[99,403,404,409],{},[117,405,406],{},[21,407,408],{},"ResponseEntity",[117,410,411],{},"Body뿐 아니라 HTTP 상태 코드와 헤더까지 명시적으로 구성하는 객체",[89,413,414],{},"주요 데이터 바인딩은 이렇게 구분",[93,416,417,427],{},[96,418,419],{},[99,420,421,424],{},[102,422,423],{},"어노테이션",[102,425,426],{},"받는 데이터",[112,428,429,442,455,465,475],{},[99,430,431,436],{},[117,432,433],{},[21,434,435],{},"@PathVariable",[117,437,438,441],{},[21,439,440],{},"\u002Fusers\u002F{id}","의 경로 값",[99,443,444,449],{},[117,445,446],{},[21,447,448],{},"@RequestParam",[117,450,451,454],{},[21,452,453],{},"?name=min"," 같은 쿼리 파라미터",[99,456,457,462],{},[117,458,459],{},[21,460,461],{},"@RequestBody",[117,463,464],{},"JSON Body를 Java DTO로 변환",[99,466,467,472],{},[117,468,469],{},[21,470,471],{},"@RequestHeader",[117,473,474],{},"Authorization 등의 HTTP Header",[99,476,477,482],{},[117,478,479],{},[21,480,481],{},"@CookieValue",[117,483,484],{},"HTTP Cookie 값",[84,486,488],{"id":487},"d-계층-구저-controller-service-repository","D. 계층 구저 : Controller, Service, Repository",[89,490,491],{},"Controller : HTTP 요청, 응답, URL 매핑, DTO 변환, 검증\nService : 비즈니스 규칙, 여러 Repositrory 조합, 트랜잭션 경계\nRepository : DB CRUD와 데이터 접근 기술을 숨기는 계층",[93,493,494,507],{},[96,495,496],{},[99,497,498,501,504],{},[102,499,500],{},"계층",[102,502,503],{},"넣어야 할 것",[102,505,506],{},"넣지 않는 편이 좋은 것",[112,508,509,520,531],{},[99,510,511,514,517],{},[117,512,513],{},"Controller",[117,515,516],{},"HTTP 요청 처리, DTO 검증, 상태 코드 결정",[117,518,519],{},"복잡한 비즈니스 규칙, SQL",[99,521,522,525,528],{},[117,523,524],{},"Service",[117,526,527],{},"업무 규칙, 트랜잭션, Repository 조합",[117,529,530],{},"HTTP,  JSON 세부 처리",[99,532,533,536,539],{},[117,534,535],{},"Repository",[117,537,538],{},"조회·저장·삭제",[117,540,541],{},"서비스 정책, 화면 요구사항",[84,543,545],{"id":544},"e-ioc와-di","E. IoC와 DI",[93,547,548,556],{},[96,549,550],{},[99,551,552,554],{},[102,553,247],{},[102,555,250],{},[112,557,558,566,578,586,594,602],{},[99,559,560,563],{},[117,561,562],{},"Dependency",[117,564,565],{},"한 객체가 기능 수행을 위해 다른 객체를 사용하는 관계",[99,567,568,571],{},[117,569,570],{},"DI, Dependency Injection",[117,572,573,574,577],{},"필요한 객체를 직접 ",[21,575,576],{},"new","하지 않고 외부에서 주입받는 방식",[99,579,580,583],{},[117,581,582],{},"IoC, Inversion of Control",[117,584,585],{},"객체 생성, 조립의 제어권이 개발자에서 Spring Container로 넘어가는 원리",[99,587,588,591],{},[117,589,590],{},"IoC Container",[117,592,593],{},"Bean 생성, 의존성 주입, 생명주기 관리를 담당하는 Spring의 객체 관리 공간",[99,595,596,599],{},[117,597,598],{},"ApplicationContext",[117,600,601],{},"실무에서 주로 사용하는 Spring IoC Container 구현체",[99,603,604,607],{},[117,605,606],{},"Singleton Bean",[117,608,609],{},"기본적으로 Container 하나당 하나만 생성되어 공유되는 Bean",[84,611,613],{"id":612},"f-proxy와-aop","F. Proxy와 AOP",[89,615,616],{},"이 둘은 구분해야 한다.",[618,619,620],"blockquote",{},[89,621,622],{},"AOP적 설계를 구현하는 좋은 방법 : Proxy",[93,624,625,634],{},[96,626,627],{},[99,628,629,632],{},[102,630,631],{},"개념",[102,633,107],{},[112,635,636,644,652],{},[99,637,638,641],{},[117,639,640],{},"AOP",[117,642,643],{},"무엇을, 어디에 적용할지 정하는 설계 방식",[99,645,646,649],{},[117,647,648],{},"Proxy",[117,650,651],{},"실제 메서드 호출을 앞뒤에서 가로채는 대리 객체",[99,653,654,656],{},[117,655,257],{},[117,657,658],{},"Bean을 Proxy로 감싸 AOP 기능을 자동 적용하는 프레임워크",[89,660,661],{},"Controller\n→ Service Proxy\n→ Before \u002F Around Advice\n→ 실제 UserService\n→ After Advice\n→ Controller",[93,663,664,672],{},[96,665,666],{},[99,667,668,670],{},[102,669,247],{},[102,671,250],{},[112,673,674,682,689,697,705,713,721,731,741,751,761],{},[99,675,676,679],{},[117,677,678],{},"Proxy Pattern",[117,680,681],{},"실제 객체 대신 같은 인터페이스, 기능을 가진 대리 객체가 호출을 제어하는 패턴",[99,683,684,686],{},[117,685,640],{},[117,687,688],{},"로깅, 보안, 트랜잭션처럼 여러 기능에 공통으로 걸리는 관심사를 분리하는 방식",[99,690,691,694],{},[117,692,693],{},"Aspect",[117,695,696],{},"공통 관심사를 구현한 클래스",[99,698,699,702],{},[117,700,701],{},"Target",[117,703,704],{},"Proxy가 감싸는 실제 Bean",[99,706,707,710],{},[117,708,709],{},"Pointcut",[117,711,712],{},"Advice를 적용할 메서드 범위",[99,714,715,718],{},[117,716,717],{},"Advice",[117,719,720],{},"실제 실행 전, 후에 추가로 수행할 코드",[99,722,723,728],{},[117,724,725],{},[21,726,727],{},"@Before",[117,729,730],{},"대상 메서드 실행 전 수행",[99,732,733,738],{},[117,734,735],{},[21,736,737],{},"@After",[117,739,740],{},"성공, 실패와 상관없이 실행 후 수행",[99,742,743,748],{},[117,744,745],{},[21,746,747],{},"@AfterReturning",[117,749,750],{},"정상 반환한 뒤 수행",[99,752,753,758],{},[117,754,755],{},[21,756,757],{},"@AfterThrowing",[117,759,760],{},"예외 발생 후 수행",[99,762,763,768],{},[117,764,765],{},[21,766,767],{},"@Around",[117,769,770],{},"실행 전, 후, 예외 처리를 모두 제어할 수 있는 Advice",[84,772,774],{"id":773},"g-dto와-입력값-검증","G. DTO와 입력값 검증",[93,776,777,785],{},[96,778,779],{},[99,780,781,783],{},[102,782,247],{},[102,784,250],{},[112,786,787,795,803,813,823,833,843,853],{},[99,788,789,792],{},[117,790,791],{},"DTO",[117,793,794],{},"계층 또는 네트워크 사이에서 데이터를 전달하기 위한 객체",[99,796,797,800],{},[117,798,799],{},"Entity",[117,801,802],{},"DB 테이블과 매핑되고 JPA가 관리하는 도메인 객체",[99,804,805,810],{},[117,806,807],{},[21,808,809],{},"@Valid",[117,811,812],{},"Controller에서 요청 DTO의 유효성을 검증하는 표준 어노테이션",[99,814,815,820],{},[117,816,817],{},[21,818,819],{},"@Validated",[117,821,822],{},"Spring의 확장 검증 어노테이션, 메서드 수준 검증과 AOP 기반 검증에 사용",[99,824,825,830],{},[117,826,827],{},[21,828,829],{},"@NotBlank",[117,831,832],{},"null, 빈 문자열, 공백 모두 허용하지 않음",[99,834,835,840],{},[117,836,837],{},[21,838,839],{},"@NotNull",[117,841,842],{},"null을 허용하지 않음",[99,844,845,850],{},[117,846,847],{},[21,848,849],{},"@Email",[117,851,852],{},"이메일 형식 검증",[99,854,855,864],{},[117,856,857,860,861],{},[21,858,859],{},"@Min",", ",[21,862,863],{},"@Max",[117,865,866],{},"숫자 범위 검증",[89,868,869],{},"Entity를 API 응답에 바로 쓰지 않고 DTO를 쓰는 이유는 다음과 같습니다.",[316,871,872,875,878,881],{},[319,873,874],{},"비밀번호 같은 내부 필드 노출 방지",[319,876,877],{},"API 요구사항과 DB 구조의 분리",[319,879,880],{},"요청 DTO와 응답 DTO의 역할 분리",[319,882,883],{},"양방향 연관관계 JSON 직렬화 문제 방지",[89,885,886],{},"HTTP JSON 요청\n→ Request DTO\n→ @Valid 검증\n→ Service\n→ Entity\n→ DB",[89,888,889],{},"DB Entity\n→ Response DTO\n→ JSON 응답",[84,891,893],{"id":892},"h-async","H. Async",[89,895,896],{},"@Async는 호출한 스레드와 별도 스레드에서 메서드를 실행하게 하는 기능",[89,898,899],{},"Controller\n→ Async Proxy\n→ Thread Pool에 작업 위임\n→ Controller는 즉시 응답 가능\n→ 별도 Thread가 실제 작업 수행",[93,901,902,910],{},[96,903,904],{},[99,905,906,908],{},[102,907,247],{},[102,909,250],{},[112,911,912,922,932,940,950,961],{},[99,913,914,919],{},[117,915,916],{},[21,917,918],{},"@EnableAsync",[117,920,921],{},"Spring의 비동기 기능을 활성화",[99,923,924,929],{},[117,925,926],{},[21,927,928],{},"@Async",[117,930,931],{},"해당 Bean 메서드를 별도 스레드에서 실행하도록 지정",[99,933,934,937],{},[117,935,936],{},"TaskExecutor",[117,938,939],{},"비동기 작업을 수행할 스레드 풀",[99,941,942,947],{},[117,943,944],{},[21,945,946],{},"CompletableFuture",[117,948,949],{},"비동기 작업의 미래 결과를 표현하고 조합하는 객체",[99,951,952,955],{},[117,953,954],{},"Blocking",[117,956,957,960],{},[21,958,959],{},".get()","처럼 결과가 나올 때까지 현재 스레드를 기다리게 하는 방식",[99,962,963,966],{},[117,964,965],{},"Non-blocking",[117,967,968],{},"Future를 반환하거나 콜백으로 처리해 현재 스레드를 기다리지 않게 하는 방식",[84,970,972],{"id":971},"i-jpa와-repository","I. JPA와 Repository",[93,974,975,983],{},[96,976,977],{},[99,978,979,981],{},[102,980,247],{},[102,982,250],{},[112,984,985,993,1001,1009,1016,1026,1036,1046,1056,1066,1076,1086],{},[99,986,987,990],{},[117,988,989],{},"ORM",[117,991,992],{},"Java 객체와 관계형 DB 테이블 사이를 연결하는 기술",[99,994,995,998],{},[117,996,997],{},"JPA",[117,999,1000],{},"Java ORM의 표준 명세",[99,1002,1003,1006],{},[117,1004,1005],{},"Hibernate",[117,1007,1008],{},"JPA 명세를 실제로 구현한 대표 라이브러리",[99,1010,1011,1013],{},[117,1012,799],{},[117,1014,1015],{},"테이블과 매핑되어 영속성 컨텍스트가 관리하는 객체",[99,1017,1018,1023],{},[117,1019,1020],{},[21,1021,1022],{},"@Entity",[117,1024,1025],{},"클래스를 JPA 관리 대상으로 지정",[99,1027,1028,1033],{},[117,1029,1030],{},[21,1031,1032],{},"@Id",[117,1034,1035],{},"기본키 필드 지정",[99,1037,1038,1043],{},[117,1039,1040],{},[21,1041,1042],{},"@GeneratedValue",[117,1044,1045],{},"기본키 자동 생성 전략 지정",[99,1047,1048,1053],{},[117,1049,1050],{},[21,1051,1052],{},"@Column",[117,1054,1055],{},"필드와 DB 컬럼의 세부 매핑 지정",[99,1057,1058,1063],{},[117,1059,1060],{},[21,1061,1062],{},"@Enumerated(EnumType.STRING)",[117,1064,1065],{},"Enum을 숫자가 아닌 문자열로 DB에 저장",[99,1067,1068,1073],{},[117,1069,1070],{},[21,1071,1072],{},"@Transient",[117,1074,1075],{},"DB 컬럼으로 저장하지 않을 필드 지정",[99,1077,1078,1083],{},[117,1079,1080],{},[21,1081,1082],{},"JpaRepository",[117,1084,1085],{},"CRUD, 페이징, 정렬 등을 제공하는 Spring Data JPA 인터페이스",[99,1087,1088,1091],{},[117,1089,1090],{},"Query Method",[117,1092,1093,1096],{},[21,1094,1095],{},"findByEmail","처럼 메서드 이름 규칙으로 쿼리를 자동 생성하는 방식",[84,1098,1100],{"id":1099},"j-연관관계와-영속성-컨텍스트","J. 연관관계와 영속성 컨텍스트",[93,1102,1103,1111],{},[96,1104,1105],{},[99,1106,1107,1109],{},[102,1108,247],{},[102,1110,250],{},[112,1112,1113,1121,1131,1141,1149,1159,1167,1175,1183,1191,1199,1207],{},[99,1114,1115,1118],{},[117,1116,1117],{},"외래키, FK",[117,1119,1120],{},"한 테이블이 다른 테이블의 기본키를 참조하는 컬럼",[99,1122,1123,1128],{},[117,1124,1125],{},[21,1126,1127],{},"@ManyToOne",[117,1129,1130],{},"여러 객체가 하나의 객체를 참조하는 N:1 관계",[99,1132,1133,1138],{},[117,1134,1135],{},[21,1136,1137],{},"@OneToMany",[117,1139,1140],{},"한 객체가 여러 객체를 가지는 1:N 관계",[99,1142,1143,1146],{},[117,1144,1145],{},"연관관계 주인",[117,1147,1148],{},"외래키를 관리하며 실제 관계 변경 SQL을 만드는 쪽",[99,1150,1151,1156],{},[117,1152,1153],{},[21,1154,1155],{},"@JoinColumn",[117,1157,1158],{},"외래키 컬럼 이름을 지정",[99,1160,1161,1164],{},[117,1162,1163],{},"LAZY Loading",[117,1165,1166],{},"연관 객체를 즉시 조회하지 않고 실제 접근 시 가져오는 방식",[99,1168,1169,1172],{},[117,1170,1171],{},"EAGER Loading",[117,1173,1174],{},"부모 객체 조회 시 연관 객체도 즉시 함께 가져오는 방식",[99,1176,1177,1180],{},[117,1178,1179],{},"EntityManager",[117,1181,1182],{},"엔티티의 CRUD와 영속성 컨텍스트를 관리하는 JPA 핵심 객체",[99,1184,1185,1188],{},[117,1186,1187],{},"영속성 컨텍스트",[117,1189,1190],{},"엔티티를 1차 캐시에 보관하고 상태 변화를 추적하는 작업 공간",[99,1192,1193,1196],{},[117,1194,1195],{},"Dirty Checking",[117,1197,1198],{},"영속 상태 엔티티의 변경을 감지해 UPDATE SQL을 자동 생성하는 기능",[99,1200,1201,1204],{},[117,1202,1203],{},"Flush",[117,1205,1206],{},"영속성 컨텍스트의 변경 내용을 DB에 동기화하는 작업",[99,1208,1209,1212],{},[117,1210,1211],{},"Write-behind",[117,1213,1214],{},"SQL을 바로 실행하지 않고 모아 두었다가 Flush, Commit 시점에 처리하는 방식",[84,1216,1218],{"id":1217},"k-transaction과-동시성","K. Transaction과 동시성",[89,1220,1221],{},"@Transactional은 단순히 “DB 저장 어노테이션”이 아닙니다. Spring이 Transaction Proxy를 만들고, 메서드 시작 전 트랜잭션을 열며, 성공하면 Commit, 기본적으로 RuntimeException이 발생하면 Rollback.",[89,1223,1224],{},"Service Proxy\n→ BEGIN\n→ 실제 Service 메서드\n→ 영속성 컨텍스트의 변경 감지\n→ Flush\n→ COMMIT 또는 ROLLBACK",[93,1226,1227,1235],{},[96,1228,1229],{},[99,1230,1231,1233],{},[102,1232,247],{},[102,1234,250],{},[112,1236,1237,1245,1253,1261,1269,1279,1287,1295,1303,1311],{},[99,1238,1239,1242],{},[117,1240,1241],{},"Transaction",[117,1243,1244],{},"여러 DB 작업을 하나의 논리적 작업 단위로 묶는 것",[99,1246,1247,1250],{},[117,1248,1249],{},"ACID",[117,1251,1252],{},"원자성, 일관성, 격리성, 지속성이라는 트랜잭션의 핵심 성질",[99,1254,1255,1258],{},[117,1256,1257],{},"Commit",[117,1259,1260],{},"변경 내용을 최종 반영",[99,1262,1263,1266],{},[117,1264,1265],{},"Rollback",[117,1267,1268],{},"작업 중 오류가 나면 변경을 취소",[99,1270,1271,1276],{},[117,1272,1273],{},[21,1274,1275],{},"readOnly = true",[117,1277,1278],{},"조회 중심 트랜잭션임을 명시해 최적화와 의도를 표현",[99,1280,1281,1284],{},[117,1282,1283],{},"Propagation",[117,1285,1286],{},"기존 트랜잭션이 있을 때 새 메서드가 참여·분리되는 방식",[99,1288,1289,1292],{},[117,1290,1291],{},"Self-invocation",[117,1293,1294],{},"같은 클래스 내부에서 메서드를 직접 호출해 Proxy를 거치지 않는 문제",[99,1296,1297,1300],{},[117,1298,1299],{},"Optimistic Lock",[117,1301,1302],{},"충돌이 드물다고 보고, 버전 비교로 Commit 시점에 충돌을 감지하는 방식",[99,1304,1305,1308],{},[117,1306,1307],{},"Pessimistic Lock",[117,1309,1310],{},"충돌이 잦다고 보고 DB Lock으로 다른 트랜잭션 접근을 미리 막는 방식",[99,1312,1313,1318],{},[117,1314,1315],{},[21,1316,1317],{},"@Version",[117,1319,1320],{},"낙관적 Lock에서 변경 횟수를 관리하는 필드",[10,1322,1324],{"id":1323},"l-api-문서화와-운영","L. API 문서화와 운영",[93,1326,1327,1335],{},[96,1328,1329],{},[99,1330,1331,1333],{},[102,1332,247],{},[102,1334,250],{},[112,1336,1337,1345,1353,1361,1369,1377,1385,1393],{},[99,1338,1339,1342],{},[117,1340,1341],{},"OpenAPI",[117,1343,1344],{},"REST API의 경로, 요청, 응답 규격을 표현하는 표준",[99,1346,1347,1350],{},[117,1348,1349],{},"Swagger UI",[117,1351,1352],{},"OpenAPI 문서를 웹 화면에서 조회, 테스트하는 도구",[99,1354,1355,1358],{},[117,1356,1357],{},"Actuator",[117,1359,1360],{},"Spring Boot 애플리케이션의 상태와 지표를 노출하는 운영 기능",[99,1362,1363,1366],{},[117,1364,1365],{},"Health",[117,1367,1368],{},"애플리케이션, DB 등 핵심 구성 요소의 정상 여부",[99,1370,1371,1374],{},[117,1372,1373],{},"Metrics",[117,1375,1376],{},"JVM 메모리, CPU, 요청 수, 응답 시간 등의 수치",[99,1378,1379,1382],{},[117,1380,1381],{},"Liveness Probe",[117,1383,1384],{},"프로세스가 살아 있는지 확인하는 상태 검사",[99,1386,1387,1390],{},[117,1388,1389],{},"Readiness Probe",[117,1391,1392],{},"현재 트래픽을 받을 준비가 됐는지 확인하는 상태 검사",[99,1394,1395,1398],{},[117,1396,1397],{},"Prometheus",[117,1399,1400],{},"모니터링 시스템이 수집할 수 있는 형식으로 Metrics를 제공하는 도구",[89,1402,1403],{},"주관식 퀴즈 연습",[1405,1406,1407,1410,1413,1416,1419,1422,1425,1428],"ol",{},[319,1408,1409],{},"REST : 웹페이지가 가진 객체, URI : 요청한 데이터의 인덱스, 이를 통해 식별해야할 대상을 알 수 있다. Http Method : 데이터 통신 방법. Representation : 데이터 표현 방법",[319,1411,1412],{},"\u002Fusers\u002F10이 더 적합하다 REST에서는 명사형으로 작성하는 게 더 권장되기 때문이다.",[319,1414,1415],{},"POST 데이터 삽입 요청, ?? 나머지는 모르겠는데?",[319,1417,1418],{},"서버가 사용자를 기억할 필요가 없어서, 서버의 수평확장이 용이하다.",[319,1420,1421],{},"DB에서 다시 불러올 필요없이, 캐시 메모리에서 꺼내므로 데이터 절약과 프로세싱 비용 절약으로 이어진다.",[319,1423,1424],{},"Spring은 자바를 이용해서 백엔드를 구현하는 프레임워크고, Spring Boot는 Spring 세팅을 도와주는 라이브러리다.",[319,1426,1427],{},"@SpringBootApplication -> ?",[319,1429,1430],{},"@가 붙은 클래스를 Bean으로 등록하여 관리하낟.",[89,1432,1433],{},"9.모르겠는데?",[1405,1435,1437,1440,1443,1446,1449,1452,1455,1458,1461,1464,1467,1470,1472,1474,1477,1480,1483,1486,1489,1492,1495,1498,1501,1504],{"start":1436},10,[319,1438,1439],{},"DispatcherServlet -> HandlerMapping ->  HandlerAdapter : 요청 분배해주는 거 아냐?",[319,1441,1442],{},"@Pathvariable -> 각 사용자의 아이디를 링크 뒤에 넣어주는 거 밖에 모르겠는데?",[319,1444,1445],{},"기능별로 분리해서 구현을 쉽게 하는 게 목표고, 각 계층에서 Controller의 경우에는 링크를 보고, 서비스로 넘겨주고, 서비스에서 실제 기능을 처리하고, Repositroy에서 DB와 데이터를 관리해.",[319,1447,1448],{},"모르겠다.",[319,1450,1451],{},"가짜 필드가 들어가는 걸 방지하기 위해서 필드 주입보다 생성자 주입이 더 선호된다.",[319,1453,1454],{},"Bean이 일반 Java 객체와 다른 점을 생명주기와 의존성 주입 관점에서 설명 -> Bean이 알아서 생명주기와 의존성 주입을 진행해서 사용자가 관리할 필요가 없다.",[319,1456,1457],{},"AoP는 반복되는 코드를 재작성하는 것을 방지하기 위해서 기능별로 묶은 것이고, Proxy는 이를 구현하는 방법 중 하나이다.\nproxy의 경우에 실행할 메서드 위에 선언하면, 메서드가 실행되기 전에 가로채서 먼저 자신의 메서드를 먼저 실행하고, 가로친 메서드를 실행하고, 그리고 자신의 메서드를 after로 선언하면 한번 더 실행하낟.",[319,1459,1460],{},"?",[319,1462,1463],{},"첨 듣는데",[319,1465,1466],{},"Entity를 그대로 전하면 비밀번호가 노출될 수 있다. 따라서 DTO로 변경해야 할 필요가 있다.",[319,1468,1469],{},"? 모르겠는데",[319,1471,1460],{},[319,1473,1460],{},[319,1475,1476],{},"JPA는 자바를 쿼리를 바꿔서 DB에 접근하게 해주는 클래스, 이 기능은 hibernate를 통해서 구현된다. Spring Data",[319,1478,1479],{},"@Entity : 엔터티 \u002F 테이블 정의 @Id : 주식별자  @GeneratedValue : 식별자 생성  @Column : 컬럼 생성",[319,1481,1482],{},"@ManyToOne 관계에서 외래키를 관리하는 쪽이 연관관계 주인이 되는 이유를 설명하세요. 그렇게 설정했으니까?",[319,1484,1485],{},"필요할 때만 로딩",[319,1487,1488],{},"모르겠는데",[319,1490,1491],{},"flush는 DB에 요청된 쿼리를 처리하고 한 번에 방출하는 기능이고, 그리고 Commit은 트랜젝션을 확정하는 기능",[319,1493,1494],{},"@Transactional이 붙은 Service 메서드 호출 시 Proxy가 시작, 종료 시점에 하는 일을 설명 ->",[319,1496,1497],{},"낙관적 Lock은 트랜젝션을 일단하고, 오류가 나면 롤백함. 비관적 Lock은 하나하나 트랜젝션이 끝나야 트랜젝션을 진행하는 방식이다,",[319,1499,1500],{},"아 Self-invocation이 뭔지 모르겠는데?",[319,1502,1503],{},"Acutator는 백엔드의 헬스 체크를 위한 기능이다. Swagger은 뭐냐 Swag임?",[319,1505,1460],{},[10,1507,1509],{"id":1508},"정답","------------ 정답",[1405,1511,1512,1515],{},[319,1513,1514],{},"DispatchServler -> 요청 접수, HandlerMapping -> 어떤 Controller 메서드인지 검색, HandelrAdapter -> 파라미터를 만들고 Controller 메서드 실행, HTTPMessageConverter -> Java 객체를 JSON으로 응답",[319,1516,1517],{},"IoC 와 DI",[89,1519,1520],{},"DI = UserService가 필요한 UserRepository를 외부에서 받는 것\nIoC = 그 객체를 생성하고 주입하는 제어권을 Spring이 가지는 것",[1405,1522,1523],{"start":39},[319,1524,1525],{},"AOP, Proxy",[89,1527,1528],{},"AOP :  어떤 공통 기능을 어디에 적용할지 정의\nProxy : 실제 호출을 가로채 공통 기능을 실행하는 객체\nSpring : Target Bean을 Proxy로 자동 포장",[1405,1530,1531],{"start":45},[319,1532,1533],{},"JPA 실행 구조",[316,1535,1536],{},[319,1537,1538],{},"영속성 컨텍스트 : 이 객체는 지금 DB의 어떤 데이터와 연결되어 있어~ 라고 관리해주는 것\nJPA는 Member 객체를 DB에서 가져온 뒤 영속성 컨텍스트에 보관합니다. 이후 같은 회원을 또 조회하면, 보통 DB를 다시 조회하기보다 먼저 이 공간에서 찾습니다. 이것이 1차 캐시",[89,1540,1541],{},"JpaRepository -> EntityManager -> 영속성 컨텍스트 -> Hibernate -> JDBC -> DB",[316,1543,1544,1547,1550],{},[319,1545,1546],{},"JPA는 표준",[319,1548,1549],{},"Hibernate는 JPA 구현체",[319,1551,1552],{},"Spring Data JPA는 Repository 추상화",[1405,1554,1555],{"start":51},[319,1556,1557],{},"transaction 실행",[89,1559,1560],{},"Controller -> Transaction Proxy -> BEGIN -> 실제 서비스 -> Dirty Checking -> Flush -> COMMIT",[89,1562,1563],{},"RuntimeException\n-> ROLLBACK",[10,1565,1566],{"id":1566},"문제",[89,1568,1569],{},"REST에서 Resource, URI, HTTP Method, Representation은 각각 무엇이며 어떻게 연결되나요?",[89,1571,1572],{},"\u002Fusers\u002F10과 \u002FgetUser?id=10 중 REST 관점에서 더 적절한 URI를 고르고 이유를 설명하세요.",[89,1574,1575],{},"POST, PUT, PATCH의 역할 차이를 사용자 수정 예시로 설명하세요.",[89,1577,1578],{},"REST의 Stateless 원칙이 서버 확장에 유리한 이유를 설명하세요.",[89,1580,1581],{},"REST의 Cacheable 원칙이 서버 성능에 어떤 도움을 주나요?",[89,1583,1584],{},"Spring과 Spring Boot의 차이를 자동 설정, 내장 서버, 실행 방식 관점에서 설명하세요.",[89,1586,1587],{},"@SpringBootApplication이 수행하는 대표 기능 세 가지를 설명하세요.",[89,1589,1590],{},"Component Scan은 어떤 클래스를 어떻게 Bean으로 등록하나요?",[89,1592,1593],{},"@Controller와 @RestController의 차이를 응답 처리 방식 기준으로 설명하세요.",[89,1595,1596],{},"브라우저 요청이 Controller 메서드에 도착할 때까지 DispatcherServlet, HandlerMapping, HandlerAdapter의 역할을 순서대로 설명하세요.",[89,1598,1599],{},"@PathVariable, @RequestParam, @RequestBody의 사용 상황을 각각 예로 드세요.",[89,1601,1602],{},"Controller, Service, Repository를 분리하는 이유와 각 계층의 책임을 설명하세요.",[89,1604,1605],{},"IoC와 DI의 차이를 “개발자 관점”과 “Spring Container 관점”으로 나누어 설명하세요.",[89,1607,1608],{},"생성자 주입이 필드 주입보다 권장되는 이유를 세 가지 설명하세요.",[89,1610,1611],{},"Bean이 일반 Java 객체와 다른 점을 생명주기와 의존성 주입 관점에서 설명하세요.",[89,1613,1614],{},"Proxy와 AOP의 관계를 “무엇을 정하는가, 어떻게 가로채는가” 관점으로 구분해 설명하세요.",[89,1616,1617],{},"@Around Advice가 @Before와 @After보다 할 수 있는 일을 설명하세요.",[89,1619,1620],{},"Spring AOP가 적용되지 않는 self-invocation 문제는 왜 발생하나요?",[89,1622,1623],{},"DTO와 Entity를 분리해야 하는 이유를 보안과 API 변경 관점에서 설명하세요.",[89,1625,1626],{},"@Valid와 @Validated의 사용 위치와 동작 방식 차이를 설명하세요.",[89,1628,1629],{},"@Async가 동작할 때 Proxy와 Thread Pool이 각각 하는 일을 설명하세요.",[89,1631,1632],{},"CompletableFuture.get()을 호출하면 비동기 코드가 왜 다시 대기 상태가 될 수 있나요?",[89,1634,1635],{},"JPA, Hibernate, Spring Data JPA의 관계를 설명하세요.",[89,1637,1638],{},"@Entity, @Id, @GeneratedValue, @Column의 역할을 각각 설명하세요.",[89,1640,1641],{},"@ManyToOne 관계에서 외래키를 관리하는 쪽이 연관관계 주인이 되는 이유를 설명하세요.",[89,1643,1644],{},"LAZY Loading이 무엇이며, 연관 객체에 접근할 때 어떤 일이 일어나나요?",[89,1646,1647],{},"영속성 컨텍스트의 1차 캐시와 Dirty Checking 기능을 설명하세요.",[89,1649,1650],{},"flush와 commit의 차이를 설명하세요.",[89,1652,1653],{},"@Transactional이 붙은 Service 메서드 호출 시 Proxy가 시작·종료 시점에 하는 일을 설명하세요.",[89,1655,1656],{},"낙관적 Lock과 비관적 Lock의 차이, 그리고 각각 적합한 상황을 설명하세요.",[89,1658,1659],{},"Transaction의 Self-invocation 문제를 피하기 위해 왜 별도 Bean으로 분리할 수 있나요?",[89,1661,1662],{},"Swagger UI와 Actuator의 목적 차이를 설명하세요.",[89,1664,1665],{},"Liveness Probe와 Readiness Probe를 Kubernetes 관점에서 구분해 설명하세요.",[1667,1668,1669],"style",{},"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);}",{"title":19,"searchDepth":33,"depth":33,"links":1671},[1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682],{"id":86,"depth":33,"text":87},{"id":237,"depth":33,"text":238},{"id":327,"depth":33,"text":328},{"id":487,"depth":33,"text":488},{"id":544,"depth":33,"text":545},{"id":612,"depth":33,"text":613},{"id":773,"depth":33,"text":774},{"id":892,"depth":33,"text":893},{"id":971,"depth":33,"text":972},{"id":1099,"depth":33,"text":1100},{"id":1217,"depth":33,"text":1218},[1684,1685],"Backend","SPRING","2026-08-18 19:28:21 +0900","md",null,"\u002Fbackend\u002Fspring\u002F2026\u002F08\u002F18\u002F강의교재_정리\u002F",{"layout":1691},"post",true,"\u002Fposts\u002Fbackend\u002Fspring\u002F_",{"title":5,"description":91},"posts\u002FBackend\u002FSPRING\u002F강의교재_정리",[],"x1J8ymmtLgDaVS63JEMqh2sx_05TCw7SfctKMG3dmk0",1788744785971]