[{"data":1,"prerenderedAt":1504},["ShallowReactive",2],{"post-document:\u002Fjava\u002Fspring\u002F2026\u002F08\u002F16\u002Fspring-data-jpa-basics\u002F":3},{"id":4,"title":5,"body":6,"categories":1486,"date":1487,"description":1488,"extension":1489,"image":1490,"key_concepts":1490,"last_modified_at":1490,"legacyPath":1491,"meta":1492,"navigation":277,"part":1494,"path":1495,"published":277,"robots":1490,"seo":1496,"series":1497,"stem":1498,"strengths":1490,"summary":1490,"tags":1499,"tradeoffs":1490,"__hash__":1503},"posts\u002Fposts\u002FBackend\u002FSPRING\u002FSpring\u002F2026-08-16-spring-data-jpa-basics.md","Spring 기초 Part 4: JPA, Entity와 Repository",{"type":7,"value":8,"toc":1472},"minimark",[9,13,20,23,34,37,42,200,202,206,209,254,257,291,294,303,306,308,312,315,351,357,362,364,368,536,539,574,579,660,665,685,694,699,779,784,786,790,797,811,814,830,833,906,909,937,939,943,947,1026,1029,1035,1077,1080,1097,1099,1103,1147,1150,1156,1159,1165,1167,1171,1174,1312,1375,1380,1382,1386,1441,1446,1450,1468],[10,11,5],"h2",{"id":12},"spring-기초-part-4-jpa-entity와-repository",[14,15,16],"blockquote",{},[17,18,19],"p",{},"JPA는 자바 객체와 데이터베이스 테이블을 매핑하여 객체 중심으로 데이터를 다룰 수 있게 해주는 자바 표준이다.",[17,21,22],{},"개발자는 Entity와 Repository를 작성하고, JPA 구현체는 객체 정보를 바탕으로 SQL을 만든다.",[24,25,31],"pre",{"className":26,"code":28,"language":29,"meta":30},[27],"language-text","Java 객체\n   ↓\nSpring Data JPA\n   ↓\nJPA\n   ↓\nHibernate\n   ↓\nJDBC\n   ↓\nDatabase\n","text","",[32,33,28],"code",{"__ignoreMap":30},[35,36],"hr",{},[38,39,41],"h3",{"id":40},"_1-먼저-알아둘-단어","1. 먼저 알아둘 단어",[43,44,45,61],"table",{},[46,47,48],"thead",{},[49,50,51,55,58],"tr",{},[52,53,54],"th",{},"용어",[52,56,57],{},"정의",[52,59,60],{},"쉽게 말하면",[62,63,64,76,87,98,109,123,141,152,163,174,187],"tbody",{},[49,65,66,70,73],{},[67,68,69],"td",{},"관계형 데이터베이스",[67,71,72],{},"데이터를 테이블 사이의 관계로 저장하는 시스템",[67,74,75],{},"H2, MySQL, PostgreSQL",[49,77,78,81,84],{},[67,79,80],{},"테이블",[67,82,83],{},"데이터를 행과 열로 저장하는 구조",[67,85,86],{},"사용자 목록을 저장하는 표",[49,88,89,92,95],{},[67,90,91],{},"행(Row)",[67,93,94],{},"테이블에 저장된 데이터 한 건",[67,96,97],{},"사용자 한 명",[49,99,100,103,106],{},[67,101,102],{},"컬럼(Column)",[67,104,105],{},"데이터가 가지는 속성",[67,107,108],{},"이름, 이메일, 나이",[49,110,111,114,117],{},[67,112,113],{},"기본키(PK)",[67,115,116],{},"각 행을 유일하게 구분하는 값",[67,118,119,120],{},"사용자 ",[32,121,122],{},"id",[49,124,125,128,131],{},[67,126,127],{},"ORM",[67,129,130],{},"객체와 관계형 테이블을 연결하는 기술",[67,132,133,136,137,140],{},[32,134,135],{},"User","와 ",[32,138,139],{},"users","를 연결",[49,142,143,146,149],{},[67,144,145],{},"JPA",[67,147,148],{},"자바 ORM 사용법을 정의한 표준",[67,150,151],{},"Entity와 관련 어노테이션 규칙",[49,153,154,157,160],{},[67,155,156],{},"Hibernate",[67,158,159],{},"JPA 표준을 실제로 구현한 라이브러리",[67,161,162],{},"객체를 보고 SQL을 생성",[49,164,165,168,171],{},[67,166,167],{},"JDBC",[67,169,170],{},"자바가 DB에 SQL을 전달하는 API",[67,172,173],{},"Hibernate가 생성한 SQL 전달",[49,175,176,179,182],{},[67,177,178],{},"Entity",[67,180,181],{},"JPA가 관리하고 테이블과 매핑하는 객체",[67,183,184,186],{},[32,185,135],{}," 클래스",[49,188,189,192,195],{},[67,190,191],{},"Repository",[67,193,194],{},"데이터 저장과 조회를 담당하는 계층",[67,196,197],{},[32,198,199],{},"UserRepository",[35,201],{},[38,203,205],{"id":204},"_2-orm은-왜-필요한가","2. ORM은 왜 필요한가",[17,207,208],{},"자바는 객체를 사용하고 관계형 데이터베이스는 테이블을 사용한다.",[43,210,211,221],{},[46,212,213],{},[49,214,215,218],{},[52,216,217],{},"자바 객체",[52,219,220],{},"데이터베이스",[62,222,223,230,238,246],{},[49,224,225,228],{},[67,226,227],{},"클래스",[67,229,80],{},[49,231,232,235],{},[67,233,234],{},"객체",[67,236,237],{},"행",[49,239,240,243],{},[67,241,242],{},"필드",[67,244,245],{},"컬럼",[49,247,248,251],{},[67,249,250],{},"객체 참조",[67,252,253],{},"외래키",[17,255,256],{},"두 구조가 다르기 때문에 JDBC만 사용하면 SQL 작성과 결과 변환을 직접 처리해야 한다.",[24,258,262],{"className":259,"code":260,"language":261,"meta":30,"style":30},"language-java shiki shiki-themes github-light github-dark","String sql = \"SELECT id, name, email FROM users WHERE id = ?\";\n\n\u002F\u002F Connection, PreparedStatement, ResultSet 처리\n\u002F\u002F ResultSet 값을 꺼내 User 객체로 직접 변환\n","java",[32,263,264,272,279,285],{"__ignoreMap":30},[265,266,269],"span",{"class":267,"line":268},"line",1,[265,270,271],{},"String sql = \"SELECT id, name, email FROM users WHERE id = ?\";\n",[265,273,275],{"class":267,"line":274},2,[265,276,278],{"emptyLinePlaceholder":277},true,"\n",[265,280,282],{"class":267,"line":281},3,[265,283,284],{},"\u002F\u002F Connection, PreparedStatement, ResultSet 처리\n",[265,286,288],{"class":267,"line":287},4,[265,289,290],{},"\u002F\u002F ResultSet 값을 꺼내 User 객체로 직접 변환\n",[17,292,293],{},"ORM을 사용하면 매핑 정보를 기준으로 반복 코드를 줄일 수 있다.",[24,295,297],{"className":259,"code":296,"language":261,"meta":30,"style":30},"User user = userRepository.findById(id).orElseThrow();\n",[32,298,299],{"__ignoreMap":30},[265,300,301],{"class":267,"line":268},[265,302,296],{},[17,304,305],{},"ORM이 SQL 지식을 없애주는 것은 아니다. 생성되는 SQL과 데이터베이스 구조를 이해해야 성능 문제를 찾을 수 있다.",[35,307],{},[38,309,311],{"id":310},"_3-jpa-hibernate-spring-data-jpa의-차이","3. JPA, Hibernate, Spring Data JPA의 차이",[17,313,314],{},"세 단어는 같은 뜻이 아니다.",[43,316,317,327],{},[46,318,319],{},[49,320,321,324],{},[52,322,323],{},"구분",[52,325,326],{},"역할",[62,328,329,336,343],{},[49,330,331,333],{},[67,332,145],{},[67,334,335],{},"ORM을 사용하는 인터페이스와 어노테이션을 정의한 표준",[49,337,338,340],{},[67,339,156],{},[67,341,342],{},"JPA 표준을 구현하여 실제 SQL을 생성하고 Entity를 관리",[49,344,345,348],{},[67,346,347],{},"Spring Data JPA",[67,349,350],{},"Repository 인터페이스를 쉽게 작성하도록 도와주는 Spring 프로젝트",[24,352,355],{"className":353,"code":354,"language":29,"meta":30},[27],"개발자가 UserRepository 호출\n          ↓\nSpring Data JPA가 Repository 구현 제공\n          ↓\nJPA 표준 방식으로 Entity 관리 요청\n          ↓\nHibernate가 SQL 생성\n          ↓\nJDBC가 DB에 SQL 전달\n",[32,356,354],{"__ignoreMap":30},[14,358,359],{},[17,360,361],{},"JPA는 규칙이고, Hibernate는 그 규칙의 구현체이며, Spring Data JPA는 JPA를 편하게 사용하도록 도와준다.",[35,363],{},[38,365,367],{"id":366},"_4-entity-만들기","4. Entity 만들기",[24,369,371],{"className":259,"code":370,"language":261,"meta":30,"style":30},"import jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.GenerationType;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.Table;\n\n@Entity\n@Table(name = \"users\")\npublic class User {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    @Column(nullable = false, length = 50)\n    private String name;\n\n    @Column(nullable = false, unique = true)\n    private String email;\n\n    protected User() {\n    }\n\n    public User(String name, String email) {\n        this.name = name;\n        this.email = email;\n    }\n}\n",[32,372,373,378,383,388,393,399,405,410,416,422,428,433,439,445,451,456,462,468,473,479,485,490,496,502,507,513,519,525,530],{"__ignoreMap":30},[265,374,375],{"class":267,"line":268},[265,376,377],{},"import jakarta.persistence.Column;\n",[265,379,380],{"class":267,"line":274},[265,381,382],{},"import jakarta.persistence.Entity;\n",[265,384,385],{"class":267,"line":281},[265,386,387],{},"import jakarta.persistence.GeneratedValue;\n",[265,389,390],{"class":267,"line":287},[265,391,392],{},"import jakarta.persistence.GenerationType;\n",[265,394,396],{"class":267,"line":395},5,[265,397,398],{},"import jakarta.persistence.Id;\n",[265,400,402],{"class":267,"line":401},6,[265,403,404],{},"import jakarta.persistence.Table;\n",[265,406,408],{"class":267,"line":407},7,[265,409,278],{"emptyLinePlaceholder":277},[265,411,413],{"class":267,"line":412},8,[265,414,415],{},"@Entity\n",[265,417,419],{"class":267,"line":418},9,[265,420,421],{},"@Table(name = \"users\")\n",[265,423,425],{"class":267,"line":424},10,[265,426,427],{},"public class User {\n",[265,429,431],{"class":267,"line":430},11,[265,432,278],{"emptyLinePlaceholder":277},[265,434,436],{"class":267,"line":435},12,[265,437,438],{},"    @Id\n",[265,440,442],{"class":267,"line":441},13,[265,443,444],{},"    @GeneratedValue(strategy = GenerationType.IDENTITY)\n",[265,446,448],{"class":267,"line":447},14,[265,449,450],{},"    private Long id;\n",[265,452,454],{"class":267,"line":453},15,[265,455,278],{"emptyLinePlaceholder":277},[265,457,459],{"class":267,"line":458},16,[265,460,461],{},"    @Column(nullable = false, length = 50)\n",[265,463,465],{"class":267,"line":464},17,[265,466,467],{},"    private String name;\n",[265,469,471],{"class":267,"line":470},18,[265,472,278],{"emptyLinePlaceholder":277},[265,474,476],{"class":267,"line":475},19,[265,477,478],{},"    @Column(nullable = false, unique = true)\n",[265,480,482],{"class":267,"line":481},20,[265,483,484],{},"    private String email;\n",[265,486,488],{"class":267,"line":487},21,[265,489,278],{"emptyLinePlaceholder":277},[265,491,493],{"class":267,"line":492},22,[265,494,495],{},"    protected User() {\n",[265,497,499],{"class":267,"line":498},23,[265,500,501],{},"    }\n",[265,503,505],{"class":267,"line":504},24,[265,506,278],{"emptyLinePlaceholder":277},[265,508,510],{"class":267,"line":509},25,[265,511,512],{},"    public User(String name, String email) {\n",[265,514,516],{"class":267,"line":515},26,[265,517,518],{},"        this.name = name;\n",[265,520,522],{"class":267,"line":521},27,[265,523,524],{},"        this.email = email;\n",[265,526,528],{"class":267,"line":527},28,[265,529,501],{},[265,531,533],{"class":267,"line":532},29,[265,534,535],{},"}\n",[17,537,538],{},"Entity 클래스에는 다음 조건이 필요하다.",[540,541,542,550,556,567],"ul",{},[543,544,545,546,549],"li",{},"클래스에 ",[32,547,548],{},"@Entity","를 붙인다.",[543,551,552,555],{},[32,553,554],{},"@Id","로 기본키를 지정한다.",[543,557,558,559,562,563,566],{},"JPA가 사용할 ",[32,560,561],{},"public"," 또는 ",[32,564,565],{},"protected"," 기본 생성자가 필요하다.",[543,568,569,570,573],{},"Entity 클래스 자체를 ",[32,571,572],{},"final","로 선언하지 않는다.",[575,576,578],"h4",{"id":577},"주요-어노테이션","주요 어노테이션",[43,580,581,590],{},[46,582,583],{},[49,584,585,588],{},[52,586,587],{},"어노테이션",[52,589,326],{},[62,591,592,601,611,620,630,640,650],{},[49,593,594,598],{},[67,595,596],{},[32,597,548],{},[67,599,600],{},"클래스를 JPA가 관리할 Entity로 지정",[49,602,603,608],{},[67,604,605],{},[32,606,607],{},"@Table",[67,609,610],{},"매핑할 테이블 이름 지정",[49,612,613,617],{},[67,614,615],{},[32,616,554],{},[67,618,619],{},"기본키 필드 지정",[49,621,622,627],{},[67,623,624],{},[32,625,626],{},"@GeneratedValue",[67,628,629],{},"기본키 자동 생성 전략 지정",[49,631,632,637],{},[67,633,634],{},[32,635,636],{},"@Column",[67,638,639],{},"컬럼 이름과 제약조건 설정",[49,641,642,647],{},[67,643,644],{},[32,645,646],{},"@Enumerated",[67,648,649],{},"Enum을 저장할 방식 지정",[49,651,652,657],{},[67,653,654],{},[32,655,656],{},"@Transient",[67,658,659],{},"DB 컬럼과 매핑하지 않을 필드 지정",[575,661,663],{"id":662},"generatedvalue",[32,664,626],{},[24,666,668],{"className":259,"code":667,"language":261,"meta":30,"style":30},"@Id\n@GeneratedValue(strategy = GenerationType.IDENTITY)\nprivate Long id;\n",[32,669,670,675,680],{"__ignoreMap":30},[265,671,672],{"class":267,"line":268},[265,673,674],{},"@Id\n",[265,676,677],{"class":267,"line":274},[265,678,679],{},"@GeneratedValue(strategy = GenerationType.IDENTITY)\n",[265,681,682],{"class":267,"line":281},[265,683,684],{},"private Long id;\n",[17,686,687,690,691,693],{},[32,688,689],{},"IDENTITY"," 전략은 기본키 생성을 데이터베이스에 맡긴다. 새로운 사용자를 만들 때 개발자가 ",[32,692,122],{},"를 직접 지정하지 않는다.",[575,695,697],{"id":696},"column",[32,698,636],{},[43,700,701,714],{},[46,702,703],{},[49,704,705,708,711],{},[52,706,707],{},"속성",[52,709,710],{},"의미",[52,712,713],{},"예시",[62,715,716,731,749,764],{},[49,717,718,723,726],{},[67,719,720],{},[32,721,722],{},"name",[67,724,725],{},"매핑할 컬럼명",[67,727,728],{},[32,729,730],{},"@Column(name = \"user_name\")",[49,732,733,738,744],{},[67,734,735],{},[32,736,737],{},"nullable",[67,739,740,743],{},[32,741,742],{},"NULL"," 허용 여부",[67,745,746],{},[32,747,748],{},"@Column(nullable = false)",[49,750,751,756,759],{},[67,752,753],{},[32,754,755],{},"length",[67,757,758],{},"문자열 컬럼 길이",[67,760,761],{},[32,762,763],{},"@Column(length = 50)",[49,765,766,771,774],{},[67,767,768],{},[32,769,770],{},"unique",[67,772,773],{},"중복 허용 여부",[67,775,776],{},[32,777,778],{},"@Column(unique = true)",[17,780,781,783],{},[32,782,636],{}," 설정만 믿기보다 운영 DB에는 마이그레이션 도구 등을 이용해 실제 제약조건도 함께 관리해야 한다.",[35,785],{},[38,787,789],{"id":788},"_5-repository-만들기","5. Repository 만들기",[17,791,792,793,796],{},"Spring Data JPA의 ",[32,794,795],{},"JpaRepository","를 상속하면 기본 CRUD 기능을 사용할 수 있다.",[24,798,800],{"className":259,"code":799,"language":261,"meta":30,"style":30},"public interface UserRepository extends JpaRepository\u003CUser, Long> {\n}\n",[32,801,802,807],{"__ignoreMap":30},[265,803,804],{"class":267,"line":268},[265,805,806],{},"public interface UserRepository extends JpaRepository\u003CUser, Long> {\n",[265,808,809],{"class":267,"line":274},[265,810,535],{},[17,812,813],{},"두 타입의 의미는 다음과 같다.",[540,815,816,821],{},[543,817,818,820],{},[32,819,135],{},": Repository가 관리할 Entity 타입",[543,822,823,826,827,829],{},[32,824,825],{},"Long",": ",[32,828,135],{},"의 기본키 타입",[17,831,832],{},"기본 제공 메서드는 다음과 같다.",[43,834,835,844],{},[46,836,837],{},[49,838,839,842],{},[52,840,841],{},"메서드",[52,843,326],{},[62,845,846,856,866,876,886,896],{},[49,847,848,853],{},[67,849,850],{},[32,851,852],{},"save(entity)",[67,854,855],{},"새 Entity 저장 또는 기존 Entity 반영",[49,857,858,863],{},[67,859,860],{},[32,861,862],{},"findById(id)",[67,864,865],{},"기본키로 한 건 조회",[49,867,868,873],{},[67,869,870],{},[32,871,872],{},"findAll()",[67,874,875],{},"전체 조회",[49,877,878,883],{},[67,879,880],{},[32,881,882],{},"existsById(id)",[67,884,885],{},"기본키에 해당하는 데이터 존재 여부 확인",[49,887,888,893],{},[67,889,890],{},[32,891,892],{},"delete(entity)",[67,894,895],{},"Entity 삭제",[49,897,898,903],{},[67,899,900],{},[32,901,902],{},"deleteById(id)",[67,904,905],{},"기본키로 삭제",[17,907,908],{},"메서드 이름을 분석해 조회 조건을 만들 수도 있다.",[24,910,912],{"className":259,"code":911,"language":261,"meta":30,"style":30},"Optional\u003CUser> findByEmail(String email);\n\nboolean existsByEmail(String email);\n\nList\u003CUser> findByNameContaining(String keyword);\n",[32,913,914,919,923,928,932],{"__ignoreMap":30},[265,915,916],{"class":267,"line":268},[265,917,918],{},"Optional\u003CUser> findByEmail(String email);\n",[265,920,921],{"class":267,"line":274},[265,922,278],{"emptyLinePlaceholder":277},[265,924,925],{"class":267,"line":281},[265,926,927],{},"boolean existsByEmail(String email);\n",[265,929,930],{"class":267,"line":287},[265,931,278],{"emptyLinePlaceholder":277},[265,933,934],{"class":267,"line":395},[265,935,936],{},"List\u003CUser> findByNameContaining(String keyword);\n",[35,938],{},[38,940,942],{"id":941},"_6-사용자-저장-흐름","6. 사용자 저장 흐름",[575,944,946],{"id":945},"service","Service",[24,948,950],{"className":259,"code":949,"language":261,"meta":30,"style":30},"@Service\npublic class UserService {\n\n    private final UserRepository userRepository;\n\n    public UserService(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n    @Transactional\n    public Long createUser(String name, String email) {\n        User user = new User(name, email);\n        User savedUser = userRepository.save(user);\n        return savedUser.getId();\n    }\n}\n",[32,951,952,957,962,966,971,975,980,985,989,993,998,1003,1008,1013,1018,1022],{"__ignoreMap":30},[265,953,954],{"class":267,"line":268},[265,955,956],{},"@Service\n",[265,958,959],{"class":267,"line":274},[265,960,961],{},"public class UserService {\n",[265,963,964],{"class":267,"line":281},[265,965,278],{"emptyLinePlaceholder":277},[265,967,968],{"class":267,"line":287},[265,969,970],{},"    private final UserRepository userRepository;\n",[265,972,973],{"class":267,"line":395},[265,974,278],{"emptyLinePlaceholder":277},[265,976,977],{"class":267,"line":401},[265,978,979],{},"    public UserService(UserRepository userRepository) {\n",[265,981,982],{"class":267,"line":407},[265,983,984],{},"        this.userRepository = userRepository;\n",[265,986,987],{"class":267,"line":412},[265,988,501],{},[265,990,991],{"class":267,"line":418},[265,992,278],{"emptyLinePlaceholder":277},[265,994,995],{"class":267,"line":424},[265,996,997],{},"    @Transactional\n",[265,999,1000],{"class":267,"line":430},[265,1001,1002],{},"    public Long createUser(String name, String email) {\n",[265,1004,1005],{"class":267,"line":435},[265,1006,1007],{},"        User user = new User(name, email);\n",[265,1009,1010],{"class":267,"line":441},[265,1011,1012],{},"        User savedUser = userRepository.save(user);\n",[265,1014,1015],{"class":267,"line":447},[265,1016,1017],{},"        return savedUser.getId();\n",[265,1019,1020],{"class":267,"line":453},[265,1021,501],{},[265,1023,1024],{"class":267,"line":458},[265,1025,535],{},[17,1027,1028],{},"실행 흐름은 다음과 같다.",[17,1030,1031],{},[1032,1033,1034],"strong",{},"Spring Data JPA 저장 흐름",[24,1036,1040],{"className":1037,"code":1038,"language":1039,"meta":30,"style":30},"language-mermaid shiki shiki-themes github-light github-dark","flowchart TD\n    S[Service가 User 생성] --> R[UserRepository.save 호출]\n    R --> SD[Spring Data JPA]\n    SD --> H[Hibernate가 Entity 관리]\n    H --> SQL[INSERT SQL 생성]\n    SQL --> J[JDBC가 SQL 전달]\n    J --> DB[(Database 저장)]\n","mermaid",[32,1041,1042,1047,1052,1057,1062,1067,1072],{"__ignoreMap":30},[265,1043,1044],{"class":267,"line":268},[265,1045,1046],{},"flowchart TD\n",[265,1048,1049],{"class":267,"line":274},[265,1050,1051],{},"    S[Service가 User 생성] --> R[UserRepository.save 호출]\n",[265,1053,1054],{"class":267,"line":281},[265,1055,1056],{},"    R --> SD[Spring Data JPA]\n",[265,1058,1059],{"class":267,"line":287},[265,1060,1061],{},"    SD --> H[Hibernate가 Entity 관리]\n",[265,1063,1064],{"class":267,"line":395},[265,1065,1066],{},"    H --> SQL[INSERT SQL 생성]\n",[265,1068,1069],{"class":267,"line":401},[265,1070,1071],{},"    SQL --> J[JDBC가 SQL 전달]\n",[265,1073,1074],{"class":267,"line":407},[265,1075,1076],{},"    J --> DB[(Database 저장)]\n",[17,1078,1079],{},"Hibernate는 Entity의 매핑 정보를 보고 대략 다음과 같은 SQL을 실행한다.",[24,1081,1085],{"className":1082,"code":1083,"language":1084,"meta":30,"style":30},"language-sql shiki shiki-themes github-light github-dark","INSERT INTO users (name, email)\nVALUES ('민형', 'min@example.com');\n","sql",[32,1086,1087,1092],{"__ignoreMap":30},[265,1088,1089],{"class":267,"line":268},[265,1090,1091],{},"INSERT INTO users (name, email)\n",[265,1093,1094],{"class":267,"line":274},[265,1095,1096],{},"VALUES ('민형', 'min@example.com');\n",[35,1098],{},[38,1100,1102],{"id":1101},"_7-jpa와-jdbc-비교","7. JPA와 JDBC 비교",[43,1104,1105,1113],{},[46,1106,1107],{},[49,1108,1109,1111],{},[52,1110,145],{},[52,1112,167],{},[62,1114,1115,1123,1131,1139],{},[49,1116,1117,1120],{},[67,1118,1119],{},"객체와 테이블을 매핑한다.",[67,1121,1122],{},"SQL을 직접 작성한다.",[49,1124,1125,1128],{},[67,1126,1127],{},"반복적인 CRUD 코드를 줄인다.",[67,1129,1130],{},"결과를 객체로 직접 변환한다.",[49,1132,1133,1136],{},[67,1134,1135],{},"변경 감지와 연관관계 기능을 제공한다.",[67,1137,1138],{},"실행 흐름이 SQL 중심으로 명확하다.",[49,1140,1141,1144],{},[67,1142,1143],{},"잘못 사용하면 예상하지 못한 SQL이 발생할 수 있다.",[67,1145,1146],{},"반복 코드가 많아질 수 있다.",[17,1148,1149],{},"JPA도 내부적으로 JDBC를 사용해 SQL을 전달한다.",[24,1151,1154],{"className":1152,"code":1153,"language":29,"meta":30},[27],"JPA와 JDBC 중 하나만 선택\n",[32,1155,1153],{"__ignoreMap":30},[17,1157,1158],{},"이 아니라 다음 구조에 가깝다.",[24,1160,1163],{"className":1161,"code":1162,"language":29,"meta":30},[27],"JPA \u002F Hibernate\n      ↓\n    JDBC\n      ↓\n  Database\n",[32,1164,1162],{"__ignoreMap":30},[35,1166],{},[38,1168,1170],{"id":1169},"_8-h2-연결-설정","8. H2 연결 설정",[17,1172,1173],{},"H2는 학습과 테스트에 많이 사용하는 가벼운 관계형 데이터베이스다.",[24,1175,1179],{"className":1176,"code":1177,"language":1178,"meta":30,"style":30},"language-yaml shiki shiki-themes github-light github-dark","spring:\n  datasource:\n    url: jdbc:h2:mem:testdb\n    driver-class-name: org.h2.Driver\n    username: sa\n    password:\n\n  h2:\n    console:\n      enabled: true\n      path: \u002Fh2-console\n\n  jpa:\n    hibernate:\n      ddl-auto: create-drop\n    show-sql: true\n","yaml",[32,1180,1181,1191,1198,1209,1219,1229,1236,1240,1247,1254,1265,1275,1279,1286,1293,1303],{"__ignoreMap":30},[265,1182,1183,1187],{"class":267,"line":268},[265,1184,1186],{"class":1185},"s9eBZ","spring",[265,1188,1190],{"class":1189},"sVt8B",":\n",[265,1192,1193,1196],{"class":267,"line":274},[265,1194,1195],{"class":1185},"  datasource",[265,1197,1190],{"class":1189},[265,1199,1200,1203,1205],{"class":267,"line":281},[265,1201,1202],{"class":1185},"    url",[265,1204,826],{"class":1189},[265,1206,1208],{"class":1207},"sZZnC","jdbc:h2:mem:testdb\n",[265,1210,1211,1214,1216],{"class":267,"line":287},[265,1212,1213],{"class":1185},"    driver-class-name",[265,1215,826],{"class":1189},[265,1217,1218],{"class":1207},"org.h2.Driver\n",[265,1220,1221,1224,1226],{"class":267,"line":395},[265,1222,1223],{"class":1185},"    username",[265,1225,826],{"class":1189},[265,1227,1228],{"class":1207},"sa\n",[265,1230,1231,1234],{"class":267,"line":401},[265,1232,1233],{"class":1185},"    password",[265,1235,1190],{"class":1189},[265,1237,1238],{"class":267,"line":407},[265,1239,278],{"emptyLinePlaceholder":277},[265,1241,1242,1245],{"class":267,"line":412},[265,1243,1244],{"class":1185},"  h2",[265,1246,1190],{"class":1189},[265,1248,1249,1252],{"class":267,"line":418},[265,1250,1251],{"class":1185},"    console",[265,1253,1190],{"class":1189},[265,1255,1256,1259,1261],{"class":267,"line":424},[265,1257,1258],{"class":1185},"      enabled",[265,1260,826],{"class":1189},[265,1262,1264],{"class":1263},"sj4cs","true\n",[265,1266,1267,1270,1272],{"class":267,"line":430},[265,1268,1269],{"class":1185},"      path",[265,1271,826],{"class":1189},[265,1273,1274],{"class":1207},"\u002Fh2-console\n",[265,1276,1277],{"class":267,"line":435},[265,1278,278],{"emptyLinePlaceholder":277},[265,1280,1281,1284],{"class":267,"line":441},[265,1282,1283],{"class":1185},"  jpa",[265,1285,1190],{"class":1189},[265,1287,1288,1291],{"class":267,"line":447},[265,1289,1290],{"class":1185},"    hibernate",[265,1292,1190],{"class":1189},[265,1294,1295,1298,1300],{"class":267,"line":453},[265,1296,1297],{"class":1185},"      ddl-auto",[265,1299,826],{"class":1189},[265,1301,1302],{"class":1207},"create-drop\n",[265,1304,1305,1308,1310],{"class":267,"line":458},[265,1306,1307],{"class":1185},"    show-sql",[265,1309,826],{"class":1189},[265,1311,1264],{"class":1263},[43,1313,1314,1323],{},[46,1315,1316],{},[49,1317,1318,1321],{},[52,1319,1320],{},"설정",[52,1322,326],{},[62,1324,1325,1335,1345,1355,1365],{},[49,1326,1327,1332],{},[67,1328,1329],{},[32,1330,1331],{},"datasource",[67,1333,1334],{},"연결할 DB 주소와 계정 설정",[49,1336,1337,1342],{},[67,1338,1339],{},[32,1340,1341],{},"ddl-auto",[67,1343,1344],{},"Entity를 기준으로 테이블을 관리하는 방식 설정",[49,1346,1347,1352],{},[67,1348,1349],{},[32,1350,1351],{},"create-drop",[67,1353,1354],{},"시작할 때 생성하고 종료할 때 삭제",[49,1356,1357,1362],{},[67,1358,1359],{},[32,1360,1361],{},"show-sql",[67,1363,1364],{},"Hibernate가 실행하는 SQL 출력",[49,1366,1367,1372],{},[67,1368,1369],{},[32,1370,1371],{},"h2.console.enabled",[67,1373,1374],{},"H2 웹 콘솔 활성화",[17,1376,1377,1379],{},[32,1378,1351],{},"은 애플리케이션 종료 시 테이블을 삭제하므로 운영 환경에서 사용하면 안 된다.",[35,1381],{},[38,1383,1385],{"id":1384},"핵심-정리","핵심 정리",[43,1387,1388,1398],{},[46,1389,1390],{},[49,1391,1392,1395],{},[52,1393,1394],{},"개념",[52,1396,1397],{},"한 줄 정리",[62,1399,1400,1407,1413,1420,1427,1434],{},[49,1401,1402,1404],{},[67,1403,127],{},[67,1405,1406],{},"자바 객체와 관계형 테이블을 연결하는 기술",[49,1408,1409,1411],{},[67,1410,145],{},[67,1412,148],{},[49,1414,1415,1417],{},[67,1416,156],{},[67,1418,1419],{},"JPA를 실제로 구현한 라이브러리",[49,1421,1422,1424],{},[67,1423,347],{},[67,1425,1426],{},"Repository 작성을 편하게 도와주는 Spring 프로젝트",[49,1428,1429,1431],{},[67,1430,178],{},[67,1432,1433],{},"JPA가 관리하며 테이블과 매핑되는 객체",[49,1435,1436,1438],{},[67,1437,191],{},[67,1439,1440],{},"Entity의 저장과 조회를 담당하는 데이터 접근 계층",[14,1442,1443],{},[17,1444,1445],{},"JPA를 사용한다는 것은 SQL을 몰라도 된다는 뜻이 아니라, 객체와 테이블의 매핑을 이용해 반복적인 데이터 접근 코드를 줄인다는 뜻이다.",[38,1447,1449],{"id":1448},"참고-자료","참고 자료",[540,1451,1452,1461],{},[543,1453,1454],{},[1455,1456,1460],"a",{"href":1457,"rel":1458},"https:\u002F\u002Fdocs.spring.io\u002Fspring-data\u002Fjpa\u002Freference\u002F",[1459],"nofollow","Spring Data JPA 공식 문서",[543,1462,1463],{},[1455,1464,1467],{"href":1465,"rel":1466},"https:\u002F\u002Fjakarta.ee\u002Fspecifications\u002Fpersistence\u002F",[1459],"Jakarta Persistence 공식 명세",[1469,1470,1471],"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);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":30,"searchDepth":274,"depth":274,"links":1473},[1474],{"id":12,"depth":274,"text":5,"children":1475},[1476,1477,1478,1479,1480,1481,1482,1483,1484,1485],{"id":40,"depth":281,"text":41},{"id":204,"depth":281,"text":205},{"id":310,"depth":281,"text":311},{"id":366,"depth":281,"text":367},{"id":788,"depth":281,"text":789},{"id":941,"depth":281,"text":942},{"id":1101,"depth":281,"text":1102},{"id":1169,"depth":281,"text":1170},{"id":1384,"depth":281,"text":1385},{"id":1448,"depth":281,"text":1449},[261,1186],"2026-08-16 09:00:00 +0900","ORM, JPA, Hibernate, Entity, Repository의 역할과 Spring Data JPA의 기본 CRUD 흐름을 정리한다.","md",null,"\u002Fjava\u002Fspring\u002F2026\u002F08\u002F16\u002Fspring-data-jpa-basics\u002F",{"layout":1493},"post","4","\u002Fposts\u002Fbackend\u002Fspring\u002Fspring\u002F2026-08-16-spring-data-jpa-basics",{"title":5,"description":1488},"Spring 기초","posts\u002FBackend\u002FSPRING\u002FSpring\u002F2026-08-16-spring-data-jpa-basics",[1500,1501,1502,145,156,347,178],"Java","Spring","Spring Boot","SoY3KWbTM7acqNkFUytcpAGFRrWaNpjXsuMk9FZPE0Q",1788744786218]