<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>더블에스 devlog</title>
    <link>https://doublesprogramming.tistory.com/</link>
    <description>{ Java , Spring }
walbatrossw@gmail.com</description>
    <language>ko</language>
    <pubDate>Tue, 11 Aug 2026 23:01:26 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>더블에스님</managingEditor>
    <image>
      <title>더블에스 devlog</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2739FB4B587DD92208</url>
      <link>https://doublesprogramming.tistory.com</link>
    </image>
    <item>
      <title>JPA - 엔티티 매핑</title>
      <link>https://doublesprogramming.tistory.com/260</link>
      <description>&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_layout-fx.css&quot;&gt;
&lt;style&gt;
.container { width: 100%; }
.wiki-container { width: 100%; }
.wiki-body { width: 100%; }
&lt;/style&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_default-fx.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism-default.css&quot;&gt;
&lt;title&gt;ch04-entity-mapping.md&lt;/title&gt;
&lt;script src=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism.pack.js&quot;&gt;&lt;/script&gt;


&lt;article class=&quot;markdown-body&quot;&gt;
&lt;blockquote&gt;
  &lt;p md-pos=&quot;2-161&quot;&gt;본 글은 &lt;a href=&quot;https://book.naver.com/bookdb/book_detail.nhn?bid=9252528&quot; md-pos=&quot;7-87&quot;&gt;자바 ORM 표준 JPA 프로그래밍&lt;/a&gt;를 읽고 개인적으로
  학습한 내용 복습하기 위해 작성된 글로 내용상 오류가 있을 수 있습니다. 오류가 있다면 지적 부탁 드리겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;jpa---엔티티-매핑&quot; md-pos=&quot;164-176&quot;&gt;&lt;a href=&quot;#jpa---엔티티-매핑&quot; name=&quot;jpa---엔티티-매핑&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;JPA - 엔티티 매핑&lt;/h1&gt;
&lt;p md-pos=&quot;178-267&quot;&gt;JPA를 사용할 때 엔티티와 테이블을 정확하게 매핑하는 것이 가장 중요하다. JPA는 매핑 어노테이션을 지원하는데
아래와 같이 크게 4가지로 분류할 수 있다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;268-281&quot;&gt;객체와 테이블 매핑&lt;/li&gt;
  &lt;li md-pos=&quot;281-290&quot;&gt;기본키 매핑&lt;/li&gt;
  &lt;li md-pos=&quot;290-302&quot;&gt;필드와 컬럼 매핑&lt;/li&gt;
  &lt;li md-pos=&quot;302-312&quot;&gt;연관관계 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;313-335&quot;&gt;위의 분류를 이제 차근차근 정리해보자.&lt;/p&gt;
&lt;h2 id=&quot;1-entity&quot; md-pos=&quot;339-349&quot;&gt;&lt;a href=&quot;#1-entity&quot; name=&quot;1-entity&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1. @Entity&lt;/h2&gt;
&lt;p md-pos=&quot;351-441&quot;&gt;JPA를 사용해서 테이블과 매핑할 클래스에는 &lt;code md-pos=&quot;377-384&quot;&gt;@Entity&lt;/code&gt; 어노테이션을 붙인다. &lt;code md-pos=&quot;399-406&quot;&gt;@Entity&lt;/code&gt;가 붙은 클래스는
JPA가 관리하는 것으로 엔티티라 부른다.&lt;/p&gt;
&lt;h3 id=&quot;11-속성&quot; md-pos=&quot;446-452&quot;&gt;&lt;a href=&quot;#11-속성&quot; name=&quot;11-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.1 속성&lt;/h3&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;453-510&quot;&gt;&lt;code md-pos=&quot;456-460&quot;&gt;name&lt;/code&gt; : JPA와 사용할 엔티티 이름을 지정, 사용하지 않을 경우 클래스이름이 그대로 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;12-주의사항&quot; md-pos=&quot;515-523&quot;&gt;&lt;a href=&quot;#12-주의사항&quot; name=&quot;12-주의사항&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.2 주의사항&lt;/h3&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;524-535&quot;&gt;기본생성자 필수&lt;/li&gt;
  &lt;li md-pos=&quot;535-589&quot;&gt;&lt;code md-pos=&quot;538-543&quot;&gt;final&lt;/code&gt;, &lt;code md-pos=&quot;547-551&quot;&gt;enum&lt;/code&gt;, &lt;code md-pos=&quot;555-564&quot;&gt;interface&lt;/code&gt;, &lt;code md-pos=&quot;568-573&quot;&gt;inner&lt;/code&gt; 클래스는 사용할 수 없음&lt;/li&gt;
  &lt;li md-pos=&quot;589-616&quot;&gt;저장할 필드에 &lt;code md-pos=&quot;600-605&quot;&gt;final&lt;/code&gt; 사용할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;617-728&quot;&gt;그리고 기억해야할 것은 자바에서는 기본생성자가 없을 경우 자동으로 생성해주지만 만약 파라미터가 있는 생성자가
클래스에 존재할 경우 기본생성자를 자동으로 생성해주지 않기 때문에 직접 작성해주어야한다.&lt;/p&gt;
&lt;h2 id=&quot;2-table&quot; md-pos=&quot;732-741&quot;&gt;&lt;a href=&quot;#2-table&quot; name=&quot;2-table&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2. @Table&lt;/h2&gt;
&lt;p md-pos=&quot;743-810&quot;&gt;&lt;code md-pos=&quot;744-750&quot;&gt;@Table&lt;/code&gt; 어노테이션은 엔티티와 매핑할 테이블을 지정하고, 생략시 매핑한 엔티티 이름을 테이블 이름으로 사용한다.&lt;/p&gt;
&lt;h3 id=&quot;21-속성&quot; md-pos=&quot;815-821&quot;&gt;&lt;a href=&quot;#21-속성&quot; name=&quot;21-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.1 속성&lt;/h3&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;822-844&quot;&gt;&lt;code md-pos=&quot;825-829&quot;&gt;name&lt;/code&gt; : 매핑할 테이블 이름&lt;/li&gt;
  &lt;li md-pos=&quot;844-894&quot;&gt;&lt;code md-pos=&quot;847-854&quot;&gt;catalog&lt;/code&gt; : catalog 기능이 있는 데이터베이스에서 catalog를 매핑&lt;/li&gt;
  &lt;li md-pos=&quot;894-941&quot;&gt;&lt;code md-pos=&quot;897-903&quot;&gt;schema&lt;/code&gt; : schema 기능이 있는 데이터베이스에서 schema를 매핑&lt;/li&gt;
  &lt;li md-pos=&quot;941-1018&quot;&gt;&lt;code md-pos=&quot;944-960&quot;&gt;uniqueConstraint&lt;/code&gt; : DDL 매핑 시에 유니크제약조건을 만듬, 스키마 자동생성 기능을 사용해서 DDL을 만들때만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-데이터베이스-스키마-자동생성&quot; md-pos=&quot;1022-1040&quot;&gt;&lt;a href=&quot;#3-데이터베이스-스키마-자동생성&quot; name=&quot;3-데이터베이스-스키마-자동생성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3. 데이터베이스 스키마 자동생성&lt;/h2&gt;
&lt;p md-pos=&quot;1042-1148&quot;&gt;JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 제공한다. 클래스의 매핑정보를 보면 어떤 테이블에 어떤
칼럼을 사용하는지 알 수 있다. 아래는 예제에 사용할 클래스를 작성한 것이다.&lt;/p&gt;
&lt;h3 id=&quot;31-스키마-자동-생성을-위한-클래스-작성&quot; md-pos=&quot;1153-1177&quot;&gt;&lt;a href=&quot;#31-스키마-자동-생성을-위한-클래스-작성&quot; name=&quot;31-스키마-자동-생성을-위한-클래스-작성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.1 스키마 자동 생성을 위한 클래스 작성&lt;/h3&gt;
&lt;pre md-pos=&quot;1179-1806&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;1187-1802&quot;&gt;@Entity // 클래스와 테이블 매핑
@Table(name = &quot;MEMBER&quot;) // 매핑할 테이블 정보 명시
public class Member {

    @Id // 기본키 매핑
    @Column(name = &quot;ID&quot;) // 필드를 컬럼에 매핑
    private String id;

    @Column(name = &quot;NAME&quot;)
    private String username;

    private Integer age; // 매핑 정보가 없을 경우 필드명이 컬럼명으로 매핑

    // 회원 타입 구분
    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    // 날짜 타입 매핑
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    // 날짜 타입 매핑
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob // 길이 제한 없음
    private String description;

    // getter, setter
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;32-스키마-자동-생성-옵션-설정&quot; md-pos=&quot;1811-1830&quot;&gt;&lt;a href=&quot;#32-스키마-자동-생성-옵션-설정&quot; name=&quot;32-스키마-자동-생성-옵션-설정&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.2 스키마 자동 생성 옵션 설정&lt;/h3&gt;
&lt;p md-pos=&quot;1832-1908&quot;&gt;&lt;code md-pos=&quot;1833-1848&quot;&gt;persistence.xml&lt;/code&gt;에서 아래와 같은 속성을 추가하면 데이터베이스 테이블을 자동으로 생성해주고, 콘솔에
DDL을 출력해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;1909-2030&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-xml&quot; md-pos=&quot;1916-2026&quot;&gt;&amp;lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;create&quot; /&amp;gt;
&amp;lt;property name=&quot;hibernate.show_sql&quot; value=&quot;true&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;2031-2102&quot;&gt;예제 프로젝트 실행 후 콘솔화면을 확인해보면 아래와 같이 DDL이 출력되고, DB에 테이블이 생성되는 것을 확인
할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;2103-2435&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;2114-2431&quot;&gt;Hibernate:
    drop table MEMBER if exists
Hibernate:
    create table MEMBER (
        ID varchar(255) not null,
        age integer,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType varchar(255),
        NAME varchar(255),
        primary key (ID)
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;2436-2595&quot;&gt;위와 같이 스키마 자동생성 기능을 사용하면 애플리케이션 실행 시점에 테이터베이스 테이블이 자동으로 생성된다.
하지만 스키마 자동 생성 기능이 만든 DDL은 운영환경에서 사용할 만큼 완벽하지 않기 때문에 개발환경에서 사용하거나
매핑을 어떻게 해야하는지 참고정도로만 사용하는 것이 좋다.&lt;/p&gt;
&lt;p md-pos=&quot;2596-2634&quot;&gt;&lt;code md-pos=&quot;2597-2619&quot;&gt;hibernate.hbm2ddl.auto&lt;/code&gt;의 속성은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;2635-2682&quot;&gt;&lt;code md-pos=&quot;2638-2644&quot;&gt;create&lt;/code&gt; : 기존 테이블을 삭제하고 새로 생성, DROP + CREATE&lt;/li&gt;
  &lt;li md-pos=&quot;2682-2748&quot;&gt;&lt;code md-pos=&quot;2685-2696&quot;&gt;create-drop&lt;/code&gt; : 애플리케이션을 종료할 때 생성한 DDL을 제거, DROP + CREATE + DROP&lt;/li&gt;
  &lt;li md-pos=&quot;2748-2793&quot;&gt;&lt;code md-pos=&quot;2751-2757&quot;&gt;update&lt;/code&gt; : DB 테이블과 엔티티 매핑정보를 비교해서 변경사항만 수정&lt;/li&gt;
  &lt;li md-pos=&quot;2793-2867&quot;&gt;&lt;code md-pos=&quot;2796-2804&quot;&gt;validate&lt;/code&gt; : DB 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션 실행X, DDL수정 X&lt;/li&gt;
  &lt;li md-pos=&quot;2867-2924&quot;&gt;&lt;code md-pos=&quot;2870-2874&quot;&gt;none&lt;/code&gt; : 자동생성 기능을 사용하지않으려면 속성을 제거하거나, 유효하지않은 옵션값을 주면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;2925-3040&quot;&gt;그리고 HBM2DDL에서 주의 해야할 것은 DDL을 수정하는 옵션(create, creat-drop, update)은 운영서버에서
사용을 절대 하면 안된다. 오직 개발서버나 개발단계에서만 사용해야만 한다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;3041-3068&quot;&gt;개발 초기단계 : create, update&lt;/li&gt;
  &lt;li md-pos=&quot;3068-3096&quot;&gt;테스트 서버 : update, validate&lt;/li&gt;
  &lt;li md-pos=&quot;3096-3126&quot;&gt;스테이징, 운영서버 : validate, none&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;3127-3210&quot;&gt;JPA는 2.1부터는 스키마 자동생성기능을 표준으로 지원하지만 HBM2DDL 속성이 지원하는 update, validate 옵션을
지원하지 않는다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;3211-3256&quot;&gt;지원옵션 : none, create, drop-and-create, drop&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;33-이름-매핑-전략-변경&quot; md-pos=&quot;3261-3276&quot;&gt;&lt;a href=&quot;#33-이름-매핑-전략-변경&quot; name=&quot;33-이름-매핑-전략-변경&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.3 이름 매핑 전략 변경&lt;/h3&gt;
&lt;p md-pos=&quot;3278-3395&quot;&gt;일반적으로 단어와 단어를 구분할 때 자바는 카멜표기법을 DB는 언더스코어를 주로 사용한다. 이러한 차이를 매핑하기
하기 위해서는 &lt;code md-pos=&quot;3351-3363&quot;&gt;@Column.name&lt;/code&gt; 속성을 명시적으로 사용해서 이름을 지정해주어야 한다.&lt;/p&gt;
&lt;pre md-pos=&quot;3396-3453&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;3404-3449&quot;&gt;@Column(name = &quot;role_type&quot;)
String roleType;
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;3454-3560&quot;&gt;위와 같이 이름 매핑 전략을 직접 지정해주어도 되지만 &lt;code md-pos=&quot;3485-3500&quot;&gt;persistence.xml&lt;/code&gt;에서 아래와 같이 속성을 지정해주면
자동으로 자바의 카멜표기법을 테이블의 언더스코어 표기법으로 매핑한다.&lt;/p&gt;
&lt;pre md-pos=&quot;3561-3673&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-xml&quot; md-pos=&quot;3568-3669&quot;&gt;&amp;lt;property name=&quot;hibernate.ejb.naming_strategy&quot; value=&quot;org.hibernate.cfg.ImprovedNamingStrategy&quot; /&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;3674-3738&quot;&gt;프로젝트를 다시 실행해보면 아래와 같이 카멜표기법에서 언더스코어 표기법으로 칼럼이 매핑 된 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;3739-4075&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;3750-4071&quot;&gt;Hibernate:
    drop table member if exists
Hibernate:
    create table member (
        id varchar(255) not null,
        age integer,
        created_date timestamp,
        description clob,
        last_modified_date timestamp,
        role_type varchar(255),
        name varchar(255),
        primary key (id)
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;4-ddl-생성기능&quot; md-pos=&quot;4079-4090&quot;&gt;&lt;a href=&quot;#4-ddl-생성기능&quot; name=&quot;4-ddl-생성기능&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4. DDL 생성기능&lt;/h2&gt;
&lt;p md-pos=&quot;4092-4146&quot;&gt;회원 클래스에서 회원 이름이 필수로 입력되고, 10자를 초과하면 안된다는 제약조건을 추가해보자.&lt;/p&gt;
&lt;pre md-pos=&quot;4147-4265&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;4155-4261&quot;&gt;@Column(name = &quot;NAME&quot;, nullable = false, length = 10) // 필수입력(null 허용X), 길이는 10자
private String username;
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;4266-4303&quot;&gt;프로젝트를 다시 실행해보면 제약 조건이 아래와 같이 추가 되었다.&lt;/p&gt;
&lt;pre md-pos=&quot;4304-4667&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;4315-4663&quot;&gt;Hibernate:
    drop table member if exists
Hibernate:
    create table member (
        id varchar(255) not null,
        age integer,
        created_date timestamp,
        description clob,
        last_modified_date timestamp,
        role_type varchar(255),
        name varchar(10) not null,  // 제약조건에 의해 컬럼 생성
        primary key (id)
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;4669-4727&quot;&gt;유니크 제약조건을 만들어주는 &lt;code md-pos=&quot;4686-4692&quot;&gt;@Table&lt;/code&gt;의 &lt;code md-pos=&quot;4696-4713&quot;&gt;uniqueConstraints&lt;/code&gt;속성에 대해 알아보자.&lt;/p&gt;
&lt;p md-pos=&quot;4728-4787&quot;&gt;회원 클래스에서 테이블 어노테이션에 아래와 같이 유니크 제약조건(유일한 값만 저장)을 추가해줄 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;4788-4997&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;4796-4993&quot;&gt;@Entity
// 유니크 제약조건 추가
@Table(name = &quot;MEMBER&quot;, uniqueConstraints = {@UniqueConstraint(
        name = &quot;NAME_AGE_UNIQUE&quot;,
        columnNames = {&quot;NAME&quot;, &quot;AGE&quot;} )})
public class Member {
   // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;4997-5052&quot;&gt;프로젝트 실행 후 콘솔화면을 확인 하면 아래와 같이 제약 조건이 추가된 것 을 확인 할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;5053-5506&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;5064-5502&quot;&gt;Hibernate:
    drop table member if exists
Hibernate:
    create table member (
        id varchar(255) not null,
        age integer,
        created_date timestamp,
        description clob,
        last_modified_date timestamp,
        role_type varchar(255),
        name varchar(10) not null,
        primary key (id)
    )
Hibernate:
    alter table member
        add constraint NAME_AGE_UNIQUE  unique (name, age)  // 유니크 제약조건 변경
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;5-기본키-매핑&quot; md-pos=&quot;5510-5519&quot;&gt;&lt;a href=&quot;#5-기본키-매핑&quot; name=&quot;5-기본키-매핑&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5. 기본키 매핑&lt;/h2&gt;
&lt;p md-pos=&quot;5521-5646&quot;&gt;기본키 매핑의 경우 직접 할당할 수도 있고, 데이터베이스가 생성해주는 값을 사용할 수도 있다. 데이터베이스마다
기본키를 생성하는 방식이 다르기 때문에 JPA가 제공하는 데이터베이스 기본키 생성 전략이 아래와 같이 다양하다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;5647-5676&quot;&gt;직접할당 : 기본키를 애플리케이션에서 직접할당&lt;/li&gt;
  &lt;li md-pos=&quot;5676-5862&quot;&gt;자동생성 : 대리키 사용방식
    &lt;ul&gt;
      &lt;li md-pos=&quot;5699-5743&quot;&gt;IDENTITY : 기본키 생성을 데이터베이스에 위임, 데이터베이스에 의존&lt;/li&gt;
      &lt;li md-pos=&quot;5747-5797&quot;&gt;SEQUENCE : 데이터베이스 시퀀스를 사용하여 기본키를 할당, 데이터베이스에 의존&lt;/li&gt;
      &lt;li md-pos=&quot;5801-5837&quot;&gt;TABLE : 키 생성 테이블을 사용, 데이터베이스에 의존X&lt;/li&gt;
      &lt;li md-pos=&quot;5841-5862&quot;&gt;AUTO : 자동으로 기본키 생성&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;51-기본키-생성-전략-설정&quot; md-pos=&quot;5867-5883&quot;&gt;&lt;a href=&quot;#51-기본키-생성-전략-설정&quot; name=&quot;51-기본키-생성-전략-설정&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.1 기본키 생성 전략 설정&lt;/h3&gt;
&lt;p md-pos=&quot;5885-5945&quot;&gt;기본키 생성 전략을 사용하기 위해서는 &lt;code md-pos=&quot;5907-5921&quot;&gt;pesistence.xml&lt;/code&gt;에 아래와 같이 속성을 추가해주어야한다.&lt;/p&gt;
&lt;pre md-pos=&quot;5946-6026&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-xml&quot; md-pos=&quot;5953-6022&quot;&gt;&amp;lt;property name=&quot;hibernate.id.new_generator_mappings&quot; value=&quot;true&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;52-직접할당&quot; md-pos=&quot;6031-6039&quot;&gt;&lt;a href=&quot;#52-직접할당&quot; name=&quot;52-직접할당&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.2 직접할당&lt;/h3&gt;
&lt;p md-pos=&quot;6041-6128&quot;&gt;기본키를 직접 할당하는 방법은 아래와 같이 클래스 필드를 &lt;code md-pos=&quot;6074-6077&quot;&gt;@Id&lt;/code&gt;로 매핑을 하고, 엔티티를 저장하기 전에
애플리케이션에서 기본키를 직접 할당해주면 된다.&lt;/p&gt;
&lt;pre md-pos=&quot;6129-6377&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;6137-6373&quot;&gt;// 기본키 직접 할당 전략
@Entity
@Table(name = &quot;MEMBER_DIRECT&quot;)
public class MemberDirect {

    @Id // 기본키 매핑
    @Column(name = &quot;ID&quot;)
    private String id;

    @Column(name = &quot;NAME&quot;)
    private String username;

    // getter, setter ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;6378-6668&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;6386-6664&quot;&gt;// 기본키 직접 할당 사용 코드
for (int i = 0; i &amp;lt; 5; i++) {
    MemberDirect member = new MemberDirect();
    member.setUsername(&quot;doubles&quot; + i);
    member.setId(&quot;id00&quot; + i); // 기본키 직접 할당
    entityManager.persist(member);
    System.out.println(&quot;DIRECT member id = &quot; + member.getId());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;6669-7278&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;6680-7274&quot;&gt;// 테이블 생성
Hibernate:
    drop table member_direct if exists
Hibernate:
    create table member_direct (
        id varchar(255) not null,
        name varchar(255),
        primary key (id)
    )

// 식별자 출력
DIRECT member id = id000
DIRECT member id = id001
DIRECT member id = id002

// 엔티티 DB 테이블 저장
Hibernate:
    insert
    into
        member_direct
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_direct
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_direct
        (name, id)
    values
        (?, ?)
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;7279-7323&quot;&gt;코드를 실행한 결과를 콘솔화면에서 확인하면 위와 같은 결과를 확인할 수 있다.&lt;/p&gt;
&lt;p md-pos=&quot;7324-7350&quot;&gt;&lt;code md-pos=&quot;7325-7328&quot;&gt;@Id&lt;/code&gt;에 적용가능 자바타입은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;7350-7359&quot;&gt;자바 기본형&lt;/li&gt;
  &lt;li md-pos=&quot;7359-7365&quot;&gt;래퍼형&lt;/li&gt;
  &lt;li md-pos=&quot;7365-7374&quot;&gt;String&lt;/li&gt;
  &lt;li md-pos=&quot;7374-7391&quot;&gt;java.util.Date&lt;/li&gt;
  &lt;li md-pos=&quot;7391-7407&quot;&gt;java.sql.Date&lt;/li&gt;
  &lt;li md-pos=&quot;7407-7430&quot;&gt;java.math.BigDecimal&lt;/li&gt;
  &lt;li md-pos=&quot;7430-7453&quot;&gt;java.math.BigInteger&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;52-identity-전략&quot; md-pos=&quot;7458-7473&quot;&gt;&lt;a href=&quot;#52-identity-전략&quot; name=&quot;52-identity-전략&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.2 IDENTITY 전략&lt;/h3&gt;
&lt;p md-pos=&quot;7475-7560&quot;&gt;IDENTITY 전략은 기본키 생성을 데이터베이스에 위임하는 방식으로 주로 MySql, PostgreSQL, SQL Server,
DB2에서 사용한다.&lt;/p&gt;
&lt;p md-pos=&quot;7561-7646&quot;&gt;회원 클래스를 아래와 같이 작성하고, id 칼럼값을 지정하지 않고 저장하면 콘솔에서 확인할 수 있듯이 자동으로
기본키가 생성되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;7647-7933&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;7655-7929&quot;&gt;// 기본키 IDENTITY 전략
@Entity
@Table(name = &quot;MEMBER_IDENTITY&quot;)
public class MemberIdentity {

    @Id // 기본키 매핑
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = &quot;NAME&quot;)
    private String username;

    // getter, setter 생략...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;7934-8221&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;7942-8217&quot;&gt;// 기본키 IDENTITY 전략 사용 코드
for (int i = 0; i &amp;lt; 3; i++) {
    MemberIdentity member2 = new MemberIdentity();
    member2.setUsername(&quot;doubles&quot; + i);
    // 기본키를 직접 할당는 코드 X
    entityManager.persist(member2);
    System.out.println(&quot;IDENTITY member id = &quot; + member2.getId());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;8222-8920&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;8233-8916&quot;&gt;// 테이블 생성
Hibernate:
    drop table member_identity if exists
Hibernate:
    create table member_identity (
        id bigint generated by default as identity, // 기본키 생성 전략
        name varchar(255),
        primary key (id)
    )

// 엔티티 DB 저장
Hibernate:
    insert
    into
        member_identity
        (id, name)
    values
        (null, ?)
// 식별자 출력
IDENTITY member id = 1  

// 엔티티 DB 저장
Hibernate:
    insert
    into
        member_identity
        (id, name)
    values
        (null, ?)
// 식별자 출력
IDENTITY member id = 2

// 엔티티 DB 저장
Hibernate:
    insert
    into
        member_identity
        (id, name)
    values
        (null, ?)
// 식별자 출력
IDENTITY member id = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;8921-9048&quot;&gt;콘솔화면을 보면 기본키를 직접할당 했을 때와 차이점을 확인할 수 있다. 기본키를 직접할당 했을 때는 엔티티의
식별자가 바로 출력되었지만 IDENTITY 전략을 사용한 경우 엔티티를 DB에 저장한 뒤에 출력된 것을 볼 수 있다.&lt;/p&gt;
&lt;p md-pos=&quot;9049-9084&quot;&gt;이렇게 두 개의 전략이  차이점을 보이는 이유는 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;9085-9162&quot;&gt;엔티티가 영속상태가 되려면 식별자가 반드시 필요한데 IDENTITY전략의 경우 엔티티를 데이터베이스에 저장해야먼 식별자를 구할수 있음&lt;/li&gt;
  &lt;li md-pos=&quot;9162-9253&quot;&gt;&lt;code md-pos=&quot;9165-9188&quot;&gt;entityManager.persist()&lt;/code&gt;를 호출하는 즉시 INSERT SQL이 DB에 바로 전달되기 때문에 트랜잭션을 지원하는 쓰기 지연이 동작하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;53-sequence-전략&quot; md-pos=&quot;9258-9273&quot;&gt;&lt;a href=&quot;#53-sequence-전략&quot; name=&quot;53-sequence-전략&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.3 SEQUENCE 전략&lt;/h3&gt;
&lt;p md-pos=&quot;9275-9374&quot;&gt;SEQUENCE 전략은 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다. 시퀀스를 지원하는 Oracle,
PostgreSQL, DB2, H2에서 사용이 가능하다.&lt;/p&gt;
&lt;pre md-pos=&quot;9375-9896&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;9383-9892&quot;&gt;// SEQUENCE 전략
@Entity
@SequenceGenerator(
        name = &quot;MEMBER_SEQ_GENERATOR&quot;,  // 식별자 생성기 이름
        sequenceName = &quot;MEMBER_SEQ&quot;, // 매핑할 데이터베이스 시퀀스 이름
        initialValue = 1,  // DDL 생성시에 사용, 시퀀스 DDL을 생성할 때 처음 시작하는 수
        allocationSize = 1) // 시퀀스 한번 호출에 증가하는 수
public class MemberSequence {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
    private Long id;

    @Column(name = &quot;NAME&quot;)
    private String username;

    // getter, setter 생략
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;9897-10084&quot;&gt;우선 사용할 데이터베이스 시퀀스를 매핑해주어야 하는데 &lt;code md-pos=&quot;9928-9946&quot;&gt;@SequenceGenerator&lt;/code&gt;를 사용해서 &lt;code md-pos=&quot;9955-9975&quot;&gt;MEMBER_SEQ_GENERATOR&lt;/code&gt;라는
시퀀스 생성기를 등록했다. &lt;code md-pos=&quot;9995-10007&quot;&gt;sequenceName&lt;/code&gt;속성의 이름으로 &lt;code md-pos=&quot;10018-10028&quot;&gt;MEMBER_SEQ&lt;/code&gt;을 지정했는데 JPA는 이 시퀀스
생성기를 실제 데이터베이스의 &lt;code md-pos=&quot;10065-10075&quot;&gt;MEMBER_SEQ&lt;/code&gt;와 매핑한다.&lt;/p&gt;
&lt;p md-pos=&quot;10085-10247&quot;&gt;그리고 키 생성 전략을 &lt;code md-pos=&quot;10099-10122&quot;&gt;GenerationType.SEQUENCE&lt;/code&gt;로 설정하고 &lt;code md-pos=&quot;10131-10165&quot;&gt;generator = &quot;MEMBER_SEQ_GENERATOR&quot;&lt;/code&gt;로
방금 등록한 시퀀스 생성기를 선택한다. 이렇게 되면 id 식별자 값은 &lt;code md-pos=&quot;10208-10228&quot;&gt;MEMBER_SEQ_GENERATOR&lt;/code&gt; 시퀀스 생성기가
할당을 한다.&lt;/p&gt;
&lt;pre md-pos=&quot;10248-10499&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;10256-10495&quot;&gt;// 시퀀스 사용 코드
for (int i = 0; i &amp;lt; 3; i++) {
    MemberSequence member3 = new MemberSequence();
    member3.setUsername(&quot;doubles&quot; + i);
    entityManager.persist(member3);
    System.out.println(&quot;SEQUENCE member id = &quot; + member3.getId());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;10500-10669&quot;&gt;위의 코드를 실행하고 나면 아래와 같이 콘솔화면을 확인 할 수 있다. 콘솔화면에 출력된 내용을 살펴보면 회원 테이블과
시퀀스를 생성하고 회원객체를 생성하고 저장할 때 마다 시퀀스를 호출해 1씩 증가시키는 것을 알 수 있다. 그리고
IDENTITY 전략과 다르게 쓰기지연이 가능한 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;10670-11618&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;10681-11614&quot;&gt;// 테이블 생성
Hibernate:
    drop table member_sequence if exists
Hibernate:
    drop sequence if exists MEMBER_SEQ
Hibernate:
    create table member_sequence (
        id bigint not null,
        name varchar(255),
        primary key (id)
    )

// 시퀀스 생성
Hibernate:
    create sequence MEMBER_SEQ start with 1 increment by 1

// 시퀀스 호출시 1씩 증가
Hibernate:
    call next value for MEMBER_SEQ

// 기본키 할당
SEQUENCE member id = 1

// 시퀀스 호출시 1씩 증가
Hibernate:
    call next value for MEMBER_SEQ

// 기본키 할당
SEQUENCE member id = 2

// 시퀀스 호출시 1씩 증가
Hibernate:
    call next value for MEMBER_SEQ

// 기본키 할당
SEQUENCE member id = 3

// 엔티티 DB 저장
Hibernate:
    insert
    into
        member_sequence
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_sequence
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_sequence
        (name, id)
    values
        (?, ?)
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;11619-11659&quot;&gt;&lt;code md-pos=&quot;11620-11638&quot;&gt;@SequenceGenerator&lt;/code&gt;의 속성을 정리해보면 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;11660-11680&quot;&gt;name : 식별자 생성기 이름&lt;/li&gt;
  &lt;li md-pos=&quot;11680-11741&quot;&gt;sequenceName : 데이터베이스에 등록된 시퀀스 이름, 기본값은 hibernate_sequence&lt;/li&gt;
  &lt;li md-pos=&quot;11741-11814&quot;&gt;initialValue : DDL 생성시에만 사용되는 속성, 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정, 기본값은 1&lt;/li&gt;
  &lt;li md-pos=&quot;11814-11857&quot;&gt;allocationSize : 시퀀스 호출에 증가하는 수, 기본값은 50&lt;/li&gt;
  &lt;li md-pos=&quot;11857-11903&quot;&gt;catalog, schema : 데이터베이스 catalog, schema 이름&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;11904-11979&quot;&gt;SEQUENCE 사용코드는 IDENTITY와 다를게 없지만 동작방식은 다르다. SEQUENCE 전략이 이루어지는 과정은 아래와 같다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;11980-12043&quot;&gt;&lt;code md-pos=&quot;11984-12007&quot;&gt;entityManager.persist()&lt;/code&gt;를 호출할 때 먼저 데이터베이스 시퀀스를 사용해 식별자를 조회&lt;/li&gt;
  &lt;li md-pos=&quot;12043-12079&quot;&gt;조회한 식별자를 엔티티에 할당한 뒤 영속성 컨텍스트에 저장&lt;/li&gt;
  &lt;li md-pos=&quot;12079-12110&quot;&gt;트랜젝션 커밋해서 플러시가 일어나면 엔티티를 저장&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;54-table-전략&quot; md-pos=&quot;12115-12127&quot;&gt;&lt;a href=&quot;#54-table-전략&quot; name=&quot;54-table-전략&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.4 TABLE 전략&lt;/h3&gt;
&lt;p md-pos=&quot;12129-12223&quot;&gt;TABLE 전략은 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 칼럼을 만들어 데이터베이스
시퀀스를 흉내내는 전략으로 모든 DB에서 사용이 가능하다.&lt;/p&gt;
&lt;pre md-pos=&quot;12224-12629&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;12232-12625&quot;&gt;// TABLE 전략
@Entity
@TableGenerator(name = &quot;MEMBER_SEQ_GENERATOR&quot;,  // 식별자 생성기 이름
        table = &quot;MY_SEQUENCES&quot;, // 키 생성 테이블 명
        pkColumnValue = &quot;MEMBER_SEQ&quot;, // 키로 사용할 값 이름
        allocationSize = 1) // 시퀀스 한번 호출에 증가하는 수
public class MemberTable {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
    private Long id;

    // 생략 ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;12630-12791&quot;&gt;위의 코드를 살펴보면 먼저 &lt;code md-pos=&quot;12646-12661&quot;&gt;@TableGenerator&lt;/code&gt;를 사용하여 &lt;code md-pos=&quot;12670-12690&quot;&gt;MEMBER_SEQ_GENERATOR&lt;/code&gt;라는 이름을 가진
테이블 키 생성기를 등록한다. &lt;code md-pos=&quot;12719-12731&quot;&gt;MY_SEQUENCES&lt;/code&gt;라는 테이블을 키 생성 테이블로 매핑하고, 키로 사용할 값의
이름을 &lt;code md-pos=&quot;12771-12781&quot;&gt;MEMEBR_SEQ&lt;/code&gt;라고 지정했다.&lt;/p&gt;
&lt;p md-pos=&quot;12792-12868&quot;&gt;그리고 기본키를 매핑한 곳에 테이블 전략을 사용한다고 명시하고, 키 생성기는 &lt;code md-pos=&quot;12836-12856&quot;&gt;MEMBER_SEQ_GENERATOR&lt;/code&gt;으로
지정해주었다.&lt;/p&gt;
&lt;pre md-pos=&quot;12869-13120&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;12877-13116&quot;&gt;// 기본키 TABLE 전략 사용 코드
for (int i = 0; i &amp;lt; 3; i++) {
    MemberTable member4 = new MemberTable();
    member4.setUsername(&quot;doubles&quot; + i);
    entityManager.persist(member4);
    System.out.println(&quot;TABLE member id = &quot; + member4.getId());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;13121-13276&quot;&gt;위의 코드를 실행하면 아래와 같은 결과를 출력한다. 테이블 전략은 시퀀스 대신에 테이블을 사용한다는 것만 제외하면
시퀀스 전략과 내부 동작 방식이 같다. TABLE 전략은 값을 조회하면서 SELECT 쿼리를 사용하고, 다음 값을 증가
시키기 위해 UPDATE 쿼리를 사용한다.&lt;/p&gt;
&lt;pre md-pos=&quot;13277-15056&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;13288-15052&quot;&gt;// 회원 테이블, 시퀀스 테이블 생성
Hibernate:
    drop table member_table if exists
Hibernate:
    drop table MY_SEQUENCES if exists
Hibernate:
    create table member_table (
        id bigint not null,
        name varchar(255),
        primary key (id)
    )
Hibernate:
    create table MY_SEQUENCES (
         sequence_name varchar(255) not null ,
        next_val bigint,
        primary key ( sequence_name )
    )

// 값 조회
Hibernate:
    select
        tbl.next_val
    from
        MY_SEQUENCES tbl
    where
        tbl.sequence_name=? for update

// 테이블에 값 존재하지 않을 경우 삽입
Hibernate:
    insert
    into
        MY_SEQUENCES
        (sequence_name, next_val)  
    values
        (?,?)

// 다음값 증가를 위해 업데이트
Hibernate:
    update
        MY_SEQUENCES
    set
        next_val=?  
    where
        next_val=?
        and sequence_name=?
TABLE member id = 1

// 값 조회
Hibernate:
    select
        tbl.next_val
    from
        MY_SEQUENCES tbl
    where
        tbl.sequence_name=? for update

// 다음값 증가를 위해 업데이트
Hibernate:
    update
        MY_SEQUENCES
    set
        next_val=?  
    where
        next_val=?
        and sequence_name=?
TABLE member id = 2

// 값 조회
Hibernate:
    select
        tbl.next_val
    from
        MY_SEQUENCES tbl
    where
        tbl.sequence_name=? for update

// 다음값 증가를 위해 업데이트
Hibernate:
    update
        MY_SEQUENCES
    set
        next_val=?  
    where
        next_val=?
        and sequence_name=?
TABLE member id = 3

// 앤타타 DB에 저장
Hibernate:
    insert
    into
        member_table
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_table
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_table
        (name, id)
    values
        (?, ?)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;55-auto-전략&quot; md-pos=&quot;15061-15072&quot;&gt;&lt;a href=&quot;#55-auto-전략&quot; name=&quot;55-auto-전략&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.5 AUTO 전략&lt;/h3&gt;
&lt;p md-pos=&quot;15074-15147&quot;&gt;AUTO 전략은 선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.&lt;/p&gt;
&lt;pre md-pos=&quot;15148-15404&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;15156-15400&quot;&gt;// 기본키 AUTO 전략
@Entity
@Table(name = &quot;MEMBER_AUTO&quot;)
public class MemberAuto {

    @Id // 기본키 매핑
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = &quot;NAME&quot;)
    private String username;

    // 생략 ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;15405-15654&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;15413-15650&quot;&gt;// H2 DB : 기본키 Auto 전략
for (int i = 0; i &amp;lt; 3; i++) {
    MemberAuto member5 = new MemberAuto();
    member5.setUsername(&quot;doubles&quot; + i);
    entityManager.persist(member5);
    System.out.println(&quot;AUTO member id = &quot; + member5.getId());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;15655-16535&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;15666-16531&quot;&gt;// 테이블 생성
Hibernate:
    drop table member_auto if exists
Hibernate:
    drop sequence if exists hibernate_sequence
Hibernate:
    create table member_auto (
        id bigint not null,
        name varchar(255),
        primary key (id)
    )

// 시퀀스 생성
Hibernate:
    create sequence hibernate_sequence start with 1 increment by 1

// 시퀀스 호출
Hibernate:
    call next value for hibernate_sequence
AUTO member id = 1
Hibernate:
    call next value for hibernate_sequence
AUTO member id = 2
Hibernate:
    call next value for hibernate_sequence
AUTO member id = 3

// 엔티티 DB 저장
Hibernate:
    insert
    into
        member_auto
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_auto
        (name, id)
    values
        (?, ?)
Hibernate:
    insert
    into
        member_auto
        (name, id)
    values
        (?, ?)
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;16537-16634&quot;&gt;AUTO 전략의 장점은 데이터베이스를 변경해도 코드를 수정할 필요가 없다. 특히 키 생성 전략이 확정되지 않은
개발 초기단계나 프로토 타입 개발시 편리하게 사용할 수 있다.&lt;/p&gt;
&lt;h3 id=&quot;56-기본키-매핑-요약&quot; md-pos=&quot;16640-16653&quot;&gt;&lt;a href=&quot;#56-기본키-매핑-요약&quot; name=&quot;56-기본키-매핑-요약&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.6 기본키 매핑 요약&lt;/h3&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;16655-16727&quot;&gt;직접할당 : &lt;code md-pos=&quot;16666-16678&quot;&gt;em.persist()&lt;/code&gt;를 호출하기전에 애플리케이션에서 직접 식별자 값을 할당해야한다. 값이 없으면 예외발생&lt;/li&gt;
  &lt;li md-pos=&quot;16727-16780&quot;&gt;SEQUENCE : 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장&lt;/li&gt;
  &lt;li md-pos=&quot;16780-16838&quot;&gt;TABLE : 데이터베이스 시퀀스 생성요 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장&lt;/li&gt;
  &lt;li md-pos=&quot;16838-16924&quot;&gt;IDENTITY : 테이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장(테이블에 데이터를 저장해야 식별자 값 획득 가능)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;6-필드와-칼럼-매핑--레퍼런스&quot; md-pos=&quot;16928-16947&quot;&gt;&lt;a href=&quot;#6-필드와-칼럼-매핑--레퍼런스&quot; name=&quot;6-필드와-칼럼-매핑--레퍼런스&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6. 필드와 칼럼 매핑 : 레퍼런스&lt;/h2&gt;
&lt;p md-pos=&quot;16949-16978&quot;&gt;필드와 칼럼 매핑을 간단하게 분류하면 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;16979-17143&quot;&gt;필드와 컬럼 매핑
    &lt;ul&gt;
      &lt;li md-pos=&quot;16993-17013&quot;&gt;&lt;code md-pos=&quot;16996-17003&quot;&gt;@Column&lt;/code&gt; : 컬럼 매핑&lt;/li&gt;
      &lt;li md-pos=&quot;17015-17047&quot;&gt;&lt;code md-pos=&quot;17018-17029&quot;&gt;@Enumerated&lt;/code&gt; : 자바 enum 타입 매핑&lt;/li&gt;
      &lt;li md-pos=&quot;17049-17074&quot;&gt;&lt;code md-pos=&quot;17052-17061&quot;&gt;@Temporal&lt;/code&gt; : 날짜 타입 매핑&lt;/li&gt;
      &lt;li md-pos=&quot;17076-17105&quot;&gt;&lt;code md-pos=&quot;17079-17083&quot;&gt;@Lob&lt;/code&gt; : BLOB, CLOB 타입을 매핑&lt;/li&gt;
      &lt;li md-pos=&quot;17107-17143&quot;&gt;&lt;code md-pos=&quot;17110-17120&quot;&gt;@Transient&lt;/code&gt; : 특정 필드를 DB에 매핑하지 않음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;17143-17186&quot;&gt;기타
    &lt;ul&gt;
      &lt;li md-pos=&quot;17150-17186&quot;&gt;&lt;code md-pos=&quot;17153-17160&quot;&gt;@Access&lt;/code&gt; : JPA가 엔티티에 접근하는 방식을 지정&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;17187-17209&quot;&gt;이 분류에 따라 좀더 자세히 알아보자.&lt;/p&gt;
&lt;h3 id=&quot;61-column&quot; md-pos=&quot;17214-17225&quot;&gt;&lt;a href=&quot;#61-column&quot; name=&quot;61-column&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.1 @Column&lt;/h3&gt;
&lt;p md-pos=&quot;17227-17259&quot;&gt;&lt;code md-pos=&quot;17228-17235&quot;&gt;@Column&lt;/code&gt;은 객체 필드를 테이블 칼럼에 매핑한다.&lt;/p&gt;
&lt;h4 id=&quot;611-속성&quot; md-pos=&quot;17265-17273&quot;&gt;&lt;a href=&quot;#611-속성&quot; name=&quot;611-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.1.1 속성&lt;/h4&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;17275-17324&quot;&gt;&lt;code md-pos=&quot;17278-17282&quot;&gt;name&lt;/code&gt; 속성 - 필드와 매핑할 테이블의 컬럼 이름, 기본값은 객체의 필드 이름&lt;/li&gt;
  &lt;li md-pos=&quot;17324-17369&quot;&gt;&lt;code md-pos=&quot;17327-17335&quot;&gt;nullable&lt;/code&gt; 속성 - null 값의 허용여부를 설정, 기본값 true&lt;/li&gt;
  &lt;li md-pos=&quot;17369-17442&quot;&gt;&lt;code md-pos=&quot;17372-17378&quot;&gt;unique&lt;/code&gt; 속성 - 한 컬럼에 간단한 유니크 제약조건을 걸 때 사용, 만약 두 컬럼이상일 경우 클래스 레벨에서 사용해야함&lt;/li&gt;
  &lt;li md-pos=&quot;17442-17499&quot;&gt;&lt;code md-pos=&quot;17445-17451&quot;&gt;length&lt;/code&gt; 속성 - 문자 길이 제약조건, &lt;code md-pos=&quot;17471-17477&quot;&gt;String&lt;/code&gt; 타입일 경우만 사용, 기본값 255&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;612-주의사항&quot; md-pos=&quot;17505-17515&quot;&gt;&lt;a href=&quot;#612-주의사항&quot; name=&quot;612-주의사항&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.1.2 주의사항&lt;/h4&gt;
&lt;p md-pos=&quot;17517-17630&quot;&gt;주의해야 할 것은 자바의 기본타입의 경우 &lt;code md-pos=&quot;17541-17548&quot;&gt;@Column&lt;/code&gt;을 사용하면 &lt;code md-pos=&quot;17557-17573&quot;&gt;nullable = false&lt;/code&gt;로 지정하는 것이
안전하다. 그 이유는 자바 기본타입의 경우 null값을 입력할 수 없기 때문이다.&lt;/p&gt;
&lt;h3 id=&quot;62-enumerated&quot; md-pos=&quot;17635-17650&quot;&gt;&lt;a href=&quot;#62-enumerated&quot; name=&quot;62-enumerated&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.2 @Enumerated&lt;/h3&gt;
&lt;p md-pos=&quot;17652-17692&quot;&gt;&lt;code md-pos=&quot;17653-17664&quot;&gt;@Enumerated&lt;/code&gt;는 자바의 enum 타입을 매핑할 때 사용한다.&lt;/p&gt;
&lt;h4 id=&quot;621-예&quot; md-pos=&quot;17698-17705&quot;&gt;&lt;a href=&quot;#621-예&quot; name=&quot;621-예&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.2.1 예&lt;/h4&gt;
&lt;pre md-pos=&quot;17707-17763&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;17715-17759&quot;&gt;// enum 클래스
enum RoleType {
  ADMIN, USER
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;17764-17903&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;17772-17899&quot;&gt;// enum 매핑
@Enumerated(EnumType.STRING)
private RoleType roleType1;

@Enumerated(EnumType.ORDINAL)
private RoleType roleType2;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;17904-18042&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;17912-18038&quot;&gt;// enum 사용
member1.setRoleType(roleType1.ADMIN); // DB에 문자 ADMIN으로 저장

member2.setRoleType(roleType2.ADMIN); // DB에 숫자 0으로 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;622-속성&quot; md-pos=&quot;18049-18057&quot;&gt;&lt;a href=&quot;#622-속성&quot; name=&quot;622-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.2.2 속성&lt;/h4&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;18059-18146&quot;&gt;
    &lt;p md-pos=&quot;18061-18080&quot;&gt;&lt;code md-pos=&quot;18062-18078&quot;&gt;EnumType.ORDINAL&lt;/code&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;18082-18104&quot;&gt;enum 순서를 데이터베이스에 저장&lt;/li&gt;
      &lt;li md-pos=&quot;18106-18124&quot;&gt;DB에 저장되는 크기가 작음&lt;/li&gt;
      &lt;li md-pos=&quot;18126-18146&quot;&gt;저장된 enum의 순서변경 불가&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;18147-18245&quot;&gt;
    &lt;p md-pos=&quot;18149-18167&quot;&gt;&lt;code md-pos=&quot;18150-18165&quot;&gt;EnumType.STRING&lt;/code&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;18169-18191&quot;&gt;enum 이름을 데이터베이스에 저장&lt;/li&gt;
      &lt;li md-pos=&quot;18193-18214&quot;&gt;DB에 저장되는 크기가 비교적 큼&lt;/li&gt;
      &lt;li md-pos=&quot;18216-18245&quot;&gt;저장된 enum의 순서가 바뀌거나 추가되도 안전&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;63-temporal&quot; md-pos=&quot;18250-18263&quot;&gt;&lt;a href=&quot;#63-temporal&quot; name=&quot;63-temporal&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.3 @Temporal&lt;/h3&gt;
&lt;p md-pos=&quot;18265-18324&quot;&gt;날짜 타입(&lt;code md-pos=&quot;18272-18286&quot;&gt;java.util.Date&lt;/code&gt;, &lt;code md-pos=&quot;18290-18308&quot;&gt;java.util.Calendar&lt;/code&gt;)을 매핑할 때 사용한다.&lt;/p&gt;
&lt;h4 id=&quot;631-속성&quot; md-pos=&quot;18330-18338&quot;&gt;&lt;a href=&quot;#631-속성&quot; name=&quot;631-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.3.1 속성&lt;/h4&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;18340-18403&quot;&gt;&lt;code md-pos=&quot;18343-18360&quot;&gt;TemporalType.DATE&lt;/code&gt; : 날짜, 데이터베이스 date 타입과 매핑, ex) 2017-01-01&lt;/li&gt;
  &lt;li md-pos=&quot;18403-18464&quot;&gt;&lt;code md-pos=&quot;18406-18423&quot;&gt;TemporalType.TIME&lt;/code&gt; : 시간, 데이터베이스 time 타입과 매핑, ex) 01:00:00&lt;/li&gt;
  &lt;li md-pos=&quot;18464-18549&quot;&gt;&lt;code md-pos=&quot;18467-18489&quot;&gt;TemporalType.TIMESTAMP&lt;/code&gt; : 날짜와 시간 데이터베이스 timestamp 타입과 매핑, ex) 2017-01-01 01:00:00&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;632-예&quot; md-pos=&quot;18555-18562&quot;&gt;&lt;a href=&quot;#632-예&quot; name=&quot;632-예&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.3.2 예&lt;/h4&gt;
&lt;pre md-pos=&quot;18564-18754&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;18572-18750&quot;&gt;@Temporal(TemporalType.DATE)
private Date date; // 날짜

@Temporal(TemporalType.TIME)
private Date time; // 시간

@Temporal(TemporalType.TIMESTAMP)
private Date timestamp; // 날짜와 시간
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;64-lob&quot; md-pos=&quot;18760-18768&quot;&gt;&lt;a href=&quot;#64-lob&quot; name=&quot;64-lob&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.4 @Lob&lt;/h3&gt;
&lt;p md-pos=&quot;18770-18798&quot;&gt;데이터베이스 BLOB, CLOB 타입과 매핑한다.&lt;/p&gt;
&lt;h4 id=&quot;641-속성&quot; md-pos=&quot;18804-18812&quot;&gt;&lt;a href=&quot;#641-속성&quot; name=&quot;641-속성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.4.1 속성&lt;/h4&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;18814-18832&quot;&gt;지정할 수 있는 속성이 없음&lt;/li&gt;
  &lt;li md-pos=&quot;18832-18950&quot;&gt;매핑하는 필드 타입이 문자면 CLOB으로 매핑, 나머지는 BLOB으로 매핑
    &lt;ul&gt;
      &lt;li md-pos=&quot;18878-18917&quot;&gt;CLOB - String, char[], java.sql.CLOB&lt;/li&gt;
      &lt;li md-pos=&quot;18919-18950&quot;&gt;BLOB - byte[], java.sql.BLOB&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;642-예&quot; md-pos=&quot;18956-18963&quot;&gt;&lt;a href=&quot;#642-예&quot; name=&quot;642-예&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.4.2 예&lt;/h4&gt;
&lt;pre md-pos=&quot;18965-19038&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;18973-19034&quot;&gt;@Lob
private String lobString;

@Lob
private byte[] lobByte;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;65-transient&quot; md-pos=&quot;19043-19057&quot;&gt;&lt;a href=&quot;#65-transient&quot; name=&quot;65-transient&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.5 @Transient&lt;/h3&gt;
&lt;p md-pos=&quot;19059-19094&quot;&gt;&lt;code md-pos=&quot;19060-19070&quot;&gt;@Transient&lt;/code&gt;는 특정 필드를 DB에 매핑하지 않는다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;19095-19123&quot;&gt;데이터베이스에 저장하지 않고, 조회도 하지않음&lt;/li&gt;
  &lt;li md-pos=&quot;19123-19153&quot;&gt;객체에 임시로 어떤 값을 보관하고 싶을 경우 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;66-access&quot; md-pos=&quot;19158-19169&quot;&gt;&lt;a href=&quot;#66-access&quot; name=&quot;66-access&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.6 @Access&lt;/h3&gt;
&lt;p md-pos=&quot;19171-19207&quot;&gt;&lt;code md-pos=&quot;19172-19179&quot;&gt;@Access&lt;/code&gt;는 JPA가 엔티티에 접근하는 방식을 지정한다.&lt;/p&gt;
&lt;h4 id=&quot;661-접근-방식&quot; md-pos=&quot;19213-19224&quot;&gt;&lt;a href=&quot;#661-접근-방식&quot; name=&quot;661-접근-방식&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.6.1 접근 방식&lt;/h4&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;19226-19293&quot;&gt;필드 접근 : &lt;code md-pos=&quot;19237-19253&quot;&gt;AccessType.FIELD&lt;/code&gt;로 지정, 필드에 직접 접근, 접근권한이 &lt;code md-pos=&quot;19278-19285&quot;&gt;private&lt;/code&gt;이어도 가능&lt;/li&gt;
  &lt;li md-pos=&quot;19293-19351&quot;&gt;프로퍼티 접근 : &lt;code md-pos=&quot;19306-19325&quot;&gt;AccessType.PROPERTY&lt;/code&gt;로 지정,  접근자(&lt;code md-pos=&quot;19338-19344&quot;&gt;getter&lt;/code&gt;)를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;662-예&quot; md-pos=&quot;19357-19364&quot;&gt;&lt;a href=&quot;#662-예&quot; name=&quot;662-예&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6.6.2 예&lt;/h4&gt;
&lt;pre md-pos=&quot;19366-19493&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;19374-19489&quot;&gt;// 필드 접근
@Entity
@Access(AccessType.FIELD) // 생략 가능
public class Member {

  @Id
  private String id;

  // ....
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;19494-19683&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;19502-19679&quot;&gt;// 프로퍼티 접근
@Entity
@Access(AccessType.PROPERTY) // 생략 가능
public class Member {

  private String id;

  // ....

  @Id
  public String getId() {
    return id;
  }

  // ....
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre md-pos=&quot;19684-19998&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;19692-19994&quot;&gt;// 필드와 프로퍼티 접근 혼용
@Entity
public class Member {

  @Id
  private String id;  // 필드 접근 방식

  @Transient
  private String firstName;

  @Transient
  private String lastName;

  // ....

  @Access(AccessType.PROPERTY)  // 프로퍼티 접근 방식
  public String getFullName() {
    return firstName + lastName;
  }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;7-summery--conclusion&quot; md-pos=&quot;20002-20025&quot;&gt;&lt;a href=&quot;#7-summery--conclusion&quot; name=&quot;7-summery--conclusion&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;7. Summery / Conclusion&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;20027-20047&quot;&gt;객체 매핑 : &lt;code md-pos=&quot;20038-20045&quot;&gt;@Entity&lt;/code&gt;&lt;/li&gt;
  &lt;li md-pos=&quot;20047-20067&quot;&gt;테이블 매핑 : &lt;code md-pos=&quot;20059-20065&quot;&gt;@Table&lt;/code&gt;&lt;/li&gt;
  &lt;li md-pos=&quot;20067-20078&quot;&gt;스키마 자동생성&lt;/li&gt;
  &lt;li md-pos=&quot;20078-20144&quot;&gt;기본키 매핑 전략
    &lt;ul&gt;
      &lt;li md-pos=&quot;20092-20099&quot;&gt;직접할당&lt;/li&gt;
      &lt;li md-pos=&quot;20101-20112&quot;&gt;IDENTITY&lt;/li&gt;
      &lt;li md-pos=&quot;20114-20125&quot;&gt;SEQUENCE&lt;/li&gt;
      &lt;li md-pos=&quot;20127-20135&quot;&gt;TABLE&lt;/li&gt;
      &lt;li md-pos=&quot;20137-20144&quot;&gt;AUTO&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;20144-20233&quot;&gt;필드 / 칼럼 매핑
    &lt;ul&gt;
      &lt;li md-pos=&quot;20159-20171&quot;&gt;&lt;code md-pos=&quot;20162-20169&quot;&gt;@Column&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;20173-20189&quot;&gt;&lt;code md-pos=&quot;20176-20187&quot;&gt;@Enumerated&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;20191-20205&quot;&gt;&lt;code md-pos=&quot;20194-20203&quot;&gt;@Temporal&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;20207-20216&quot;&gt;&lt;code md-pos=&quot;20210-20214&quot;&gt;@Lob&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;20218-20233&quot;&gt;&lt;code md-pos=&quot;20221-20231&quot;&gt;@Transient&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;20233-20261&quot;&gt;필드, 프로퍼티 접근
    &lt;ul&gt;
      &lt;li md-pos=&quot;20249-20261&quot;&gt;&lt;code md-pos=&quot;20252-20259&quot;&gt;@Access&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;</description>
      <category>JPA</category>
      <category>@Access</category>
      <category>@Column</category>
      <category>@Entity</category>
      <category>@Enumerated</category>
      <category>@lLob</category>
      <category>@Temporal</category>
      <category>@Transient</category>
      <category>JPA</category>
      <category>기본키 생성 전략</category>
      <category>엔티티 매핑</category>
      <author>더블에스님</author>
      <guid isPermaLink="true">https://doublesprogramming.tistory.com/260</guid>
      <comments>https://doublesprogramming.tistory.com/260#entry260comment</comments>
      <pubDate>Fri, 15 Mar 2019 22:41:53 +0900</pubDate>
    </item>
    <item>
      <title>JPA - 영속성 관리</title>
      <link>https://doublesprogramming.tistory.com/259</link>
      <description>&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_layout-fx.css&quot;&gt;
&lt;style&gt;
.container { width: 100%; }
.wiki-container { width: 100%; }
.wiki-body { width: 100%; }
&lt;/style&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_default-fx.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism-default.css&quot;&gt;
&lt;title&gt;ch03-persistence-context.md&lt;/title&gt;
&lt;script src=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism.pack.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;blockquote&gt;
  &lt;p md-pos=&quot;2-161&quot;&gt;본 글은 &lt;a href=&quot;https://book.naver.com/bookdb/book_detail.nhn?bid=9252528&quot; md-pos=&quot;7-87&quot;&gt;자바 ORM 표준 JPA 프로그래밍&lt;/a&gt;를 읽고 개인적으로
  학습한 내용 복습하기 위해 작성된 글로 내용상 오류가 있을 수 있습니다. 오류가 있다면 지적 부탁 드리겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;jpa---영속성-관리&quot; md-pos=&quot;165-177&quot;&gt;&lt;a href=&quot;#jpa---영속성-관리&quot; name=&quot;jpa---영속성-관리&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;JPA - 영속성 관리&lt;/h1&gt;
&lt;h2 id=&quot;1-영속성-컨텍스트-기본-개념&quot; md-pos=&quot;182-199&quot;&gt;&lt;a href=&quot;#1-영속성-컨텍스트-기본-개념&quot; name=&quot;1-영속성-컨텍스트-기본-개념&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1. 영속성 컨텍스트 기본 개념&lt;/h2&gt;
&lt;p md-pos=&quot;201-323&quot;&gt;&lt;strong md-pos=&quot;203-259&quot;&gt;영속성 컨텍스트(Persistence Context)란 &amp;quot;엔티티를 영구 저장하는 환경&amp;quot;이라는 뜻이다.&lt;/strong&gt; 엔티티
매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에서 엔티티를 보관하고 관리한다.&lt;/p&gt;
&lt;p md-pos=&quot;324-378&quot;&gt;&lt;code md-pos=&quot;325-334&quot;&gt;persist()&lt;/code&gt;메서드는 엔티티 매니저를 사용해서 회원 엔티티를 영속성 컨텍스트에
저장한다.&lt;/p&gt;
&lt;h2 id=&quot;2-엔티티-생명주기&quot; md-pos=&quot;382-393&quot;&gt;&lt;a href=&quot;#2-엔티티-생명주기&quot; name=&quot;2-엔티티-생명주기&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2. 엔티티 생명주기&lt;/h2&gt;
&lt;p md-pos=&quot;395-432&quot;&gt;엔티티에는 4가지 상태가 존재하며 생명주기는 아래의 그림과 같다.&lt;/p&gt;
&lt;p md-pos=&quot;433-544&quot;&gt;&lt;img src=&quot;https://github.com/walbatrossw/jpa-study/blob/master/docs/img/entity-lifetime.png?raw=true&quot; alt=&quot;entity-lifetime&quot; md-pos=&quot;433-543&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;545-588&quot;&gt;비영속(new/transient) : 영속성 컨텍스트와 관계가 없는 상태&lt;/li&gt;
  &lt;li md-pos=&quot;588-621&quot;&gt;영속(managed) : 영속성 컨텍스트에 저장된 상태&lt;/li&gt;
  &lt;li md-pos=&quot;621-663&quot;&gt;준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태&lt;/li&gt;
  &lt;li md-pos=&quot;663-686&quot;&gt;삭제(removed) : 삭제된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;21-비영속&quot; md-pos=&quot;691-698&quot;&gt;&lt;a href=&quot;#21-비영속&quot; name=&quot;21-비영속&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.1 비영속&lt;/h3&gt;
&lt;p md-pos=&quot;700-773&quot;&gt;엔티티 객체를 생성하여 순수한 객체의 상태이며 저장하지 않은 상태를 말한다.
따라서 영속성 컨텍스트나 데이터베이스와 관련이 없다.&lt;/p&gt;
&lt;pre md-pos=&quot;774-885&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;782-881&quot;&gt;// 객체 생성 : 비영속
Member member = new Member();
member.setId(&amp;quot;id001&amp;quot;);
member.setUsername(&amp;quot;doubles&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;22-영속&quot; md-pos=&quot;890-896&quot;&gt;&lt;a href=&quot;#22-영속&quot; name=&quot;22-영속&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.2 영속&lt;/h3&gt;
&lt;p md-pos=&quot;898-969&quot;&gt;앤티티 매니저를 통해 앤티티를 영속성 컨텍스트에 저장한 상태를 말한다. 영속성 컨텍스트가 관리하는 엔티티를
영속상태라고 한다.&lt;/p&gt;
&lt;pre md-pos=&quot;970-1187&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;978-1183&quot;&gt;// 저장 : 영속
entityManager.persist(member);
// 한건 조회 : 영속
entityManager.find(&amp;quot;id001&amp;quot;);
// 목록 조회 : 영속
List&amp;lt;Member&amp;gt; members = entityManager.createQuery(&amp;quot;SELECT m FROM Member m&amp;quot;, Member.class).getResultList();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;23-준영속&quot; md-pos=&quot;1192-1199&quot;&gt;&lt;a href=&quot;#23-준영속&quot; name=&quot;23-준영속&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.3 준영속&lt;/h3&gt;
&lt;p md-pos=&quot;1201-1298&quot;&gt;영속성 컨텍스트가 관리하던 영속상태의 엔티티를 영속성 컨텍스트가 관리하지 않으면
준영속 상태가 된다. 특정 엔티티를 준영속 상태로 만드려면 아래의 메서드들을 호출하면 된다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;1298-1330&quot;&gt;&lt;code md-pos=&quot;1301-1323&quot;&gt;entityManager.detach()&lt;/code&gt; : 분리&lt;/li&gt;
  &lt;li md-pos=&quot;1330-1370&quot;&gt;&lt;code md-pos=&quot;1333-1354&quot;&gt;entityManager.close()&lt;/code&gt; : 영속성 컨텍스트 닫음&lt;/li&gt;
  &lt;li md-pos=&quot;1370-1411&quot;&gt;&lt;code md-pos=&quot;1373-1394&quot;&gt;entityManager.clear()&lt;/code&gt; : 영속성 컨텍스트 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;24-삭제&quot; md-pos=&quot;1416-1422&quot;&gt;&lt;a href=&quot;#24-삭제&quot; name=&quot;24-삭제&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.4 삭제&lt;/h3&gt;
&lt;p md-pos=&quot;1424-1454&quot;&gt;엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.&lt;/p&gt;
&lt;pre md-pos=&quot;1455-1491&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;1463-1487&quot;&gt;entityManager.remove();
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-영속성-컨텍스트-특징&quot; md-pos=&quot;1495-1509&quot;&gt;&lt;a href=&quot;#3-영속성-컨텍스트-특징&quot; name=&quot;3-영속성-컨텍스트-특징&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3. 영속성 컨텍스트 특징&lt;/h2&gt;
&lt;p md-pos=&quot;1511-1533&quot;&gt;영속성 컨텍스트의 특징은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;1534-1590&quot;&gt;영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다, 즉 영속상태는 식별자 값이 존재해야만 한다.&lt;/li&gt;
  &lt;li md-pos=&quot;1590-1652&quot;&gt;영속성 컨텍스트에 저장된 엔티티는 트랜잭션을 커밋하는 순간 데이터베이스에 반영된다. 이것을 플러시라 한다.&lt;/li&gt;
  &lt;li md-pos=&quot;1652-1727&quot;&gt;영속성 컨텍스트의 장점
    &lt;ul&gt;
      &lt;li md-pos=&quot;1669-1677&quot;&gt;1차 캐시&lt;/li&gt;
      &lt;li md-pos=&quot;1679-1688&quot;&gt;동일성 보장&lt;/li&gt;
      &lt;li md-pos=&quot;1690-1709&quot;&gt;트랜잭션을 지원하는 쓰기 지연&lt;/li&gt;
      &lt;li md-pos=&quot;1711-1718&quot;&gt;변경감지&lt;/li&gt;
      &lt;li md-pos=&quot;1720-1727&quot;&gt;지연로딩&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;1728-1774&quot;&gt;그럼 영속성 컨텍스트가 왜 필요하고 어떤 장점이 있는지 CRUD를 하면서 알아보자&lt;/p&gt;
&lt;h3 id=&quot;31-조회--1차-캐시-동일성-보장&quot; md-pos=&quot;1779-1801&quot;&gt;&lt;a href=&quot;#31-조회--1차-캐시-동일성-보장&quot; name=&quot;31-조회--1차-캐시-동일성-보장&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.1 조회 : 1차 캐시, 동일성 보장&lt;/h3&gt;
&lt;p md-pos=&quot;1803-1930&quot;&gt;영속성 컨텍스는 내부에 캐시를 가지고 있는데 이것을 1차 캐시라 한다. 영속상태의 엔티티는 이곳에 모두
저장된다. 쉽게 말하면 영속성 컨텍스트 내부에 Map이 있는데 키는 &lt;code md-pos=&quot;1900-1903&quot;&gt;@Id&lt;/code&gt;로 매핑한 식별자고 값은 엔티티
컨텍스트이다.&lt;/p&gt;
&lt;pre md-pos=&quot;1931-2669&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;1939-2665&quot;&gt;// 비영속 상태 : 객체 생성
Member member = new Memebr();
member.setId(&amp;quot;id001&amp;quot;);
member.setUsername(&amp;quot;doubles&amp;quot;);

// 영속 상태
// 1차 캐시에 저장
entityManager.persist(member); // 엔티티 저장

// 1차 캐시에 존재하는 엔티티를 조회할 경우
// 1. 1차 캐시에서 조회
// 2. 반환
Member member1 = entityManager.find(Member.class, &amp;quot;id001&amp;quot;); // 한 건 조회

// 1차 캐시에 존재하지 않는 엔티티를 조회할 경우
// 1. 1차 캐시에서 id002를 식별자로 가진 엔티티 조회
// 2. 1차 캐시에 존재하지 않기 때문에 DB에서 조회해서 엔티티를 생성
// 3. 1차 캐시에 저장
// 4. 반환
Member member2 = entityManager.find(Member.class, &amp;quot;id002&amp;quot;); // 한 건 조회

// 영속 엔티티 동일성
// 식별자가 같은 엔티티 2번 조회
Member a = entityManager.find(Member.class, &amp;quot;id001&amp;quot;);
Member b = entityManager.find(Member.class, &amp;quot;id001&amp;quot;);

// 엔티티 a와 b는 1차 캐시에 있는 같은 엔티티를 반환 받았기 때문에 같은 인스턴스
System.out.println(a == b); // true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;32-등록--트랜잭션을-지원하는-쓰기-지연&quot; md-pos=&quot;2675-2700&quot;&gt;&lt;a href=&quot;#32-등록--트랜잭션을-지원하는-쓰기-지연&quot; name=&quot;32-등록--트랜잭션을-지원하는-쓰기-지연&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.2 등록 : 트랜잭션을 지원하는 쓰기 지연&lt;/h3&gt;
&lt;pre md-pos=&quot;2702-2959&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;2710-2955&quot;&gt;// memberA, memberB 객체 생성
// 엔티티 매니저 생성, 트랜잭션 획득 ...

transaction.begin(); // 트랜잭션 시작

entityManager.persist(memberA);
entityManager.persist(memberB);
// INSERT SQL을 DB에 보내지 않음

// 커밋을 수행하는 순간 INSERT SQL을 DB에 보냄
transaction.commit(); // 트랜잭션 커밋
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;2960-3083&quot;&gt;엔티티 매니저는 트랜잭션을 커밋하기 전까지 DB에 엔티티를 저장하지 않고, 내부 쿼리 저장소에 INSERT SQL을
차곡차곡 모아둔다. 트랜잭션을 커밋할 때 모아둔 SQL을 DB에 보낸다. 이것을 쓰기 지연이라고 한다.&lt;/p&gt;
&lt;p md-pos=&quot;3084-3159&quot;&gt;트랜잭션을 커밋하면 영속성 컨텍스트는 플러시를 하는데 여기서 플러시는 영속성 컨텍스트의 변경 내용을 DB에
동기화하는 작업을 말한다.&lt;/p&gt;
&lt;h3 id=&quot;33-수정--변경-감지-지연-로딩&quot; md-pos=&quot;3164-3185&quot;&gt;&lt;a href=&quot;#33-수정--변경-감지-지연-로딩&quot; name=&quot;33-수정--변경-감지-지연-로딩&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.3 수정 : 변경 감지, 지연 로딩&lt;/h3&gt;
&lt;pre md-pos=&quot;3187-3494&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;3195-3490&quot;&gt;// 엔티티 매니저 생성, 트랜잭션 획득 ...

transaction.begin(); // 트랜잭션 시작

Member findMember = entityManager.find(Member.class, &amp;quot;id001&amp;quot;); // 영속 엔티티 조회

// 영속 엔티티 데이터 수정
findMember.setUsername(&amp;quot;더블에스&amp;quot;);
findMember.setAge(29);

//entityManager.update(findMember); // 이런 코드는 없다!

transaction.commit(); // 트랜잭션 커밋
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;3495-3623&quot;&gt;JPA에서 엔티티를 수정할 때는 위와 같이 엔티티를 조회하고 데이터만 변경해주기만 하면 된다. 수정과 관련된
메서드는 JPA에서 따로 존재하지 않는다. 이렇게 엔티티의 변경사항을 DB에 자동으로 반영하는 것을 변경감지라고 한다.&lt;/p&gt;
&lt;p md-pos=&quot;3624-3654&quot;&gt;그렇다면 변경감지 기능은 어떻게 작동하는지 알아보자.&lt;/p&gt;
&lt;p md-pos=&quot;3655-3756&quot;&gt;JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해 저장해두는데 이것을 스냅샷이라 한다. 그리고
플러시 시점에 스냅샷과 엔티티를 비교하여 변경된 엔티티를 찾게된다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;3757-3780&quot;&gt;트랜잭션 커밋 ---&amp;gt; 플러시 호출&lt;/li&gt;
  &lt;li md-pos=&quot;3780-3808&quot;&gt;엔티티와 스냅샷 비교, 변경된 엔티티를 찾음&lt;/li&gt;
  &lt;li md-pos=&quot;3808-3857&quot;&gt;변경된 엔티티가 존재하면 수정 쿼리를 생성 ---&amp;gt; 쓰기지연 SQL 저장소에 보관&lt;/li&gt;
  &lt;li md-pos=&quot;3857-3877&quot;&gt;쓰기지연 SQL을 DB에 전송&lt;/li&gt;
  &lt;li md-pos=&quot;3877-3891&quot;&gt;DB 트랜잭션 커밋&lt;/li&gt;
&lt;/ol&gt;
&lt;p md-pos=&quot;3892-3959&quot;&gt;변경 감지는 영속성 컨텍스트가 관리하는 영속상태의 엔티티에만 적용되고 비영속, 준영속 상태의 엔티티는 적용되지
않는다.&lt;/p&gt;
&lt;p md-pos=&quot;3960-4063&quot;&gt;변경감지로 인해 생성된 UDPATE SQL은 엔티티의 모든 필드를 업데이트 한다. 모든 필드를 DB에 보내면 데이터
전송량이 증가하는 단점이 존재하지만 아래와 같은 장점을 얻게 된다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;4064-4130&quot;&gt;모든 필드를 사용하면 수정 쿼리가 항상 같다. 애플리케이션 로딩시점에 수정쿼리를 미리 생성하고 재사용이 가능하다.&lt;/li&gt;
  &lt;li md-pos=&quot;4130-4178&quot;&gt;DB에 동일한 쿼리를 보내면 DB는 이전에 한번 파싱된 쿼리를 재사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;34-삭제&quot; md-pos=&quot;4183-4189&quot;&gt;&lt;a href=&quot;#34-삭제&quot; name=&quot;34-삭제&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.4 삭제&lt;/h3&gt;
&lt;pre md-pos=&quot;4191-4319&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;4199-4315&quot;&gt;Member member1 = entityManager.find(Member.class, &amp;quot;id001&amp;quot;); // 삭제 대상 엔티티 조회
entityManager.remove(member); // 엔티티 삭제
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;4319-4463&quot;&gt;엔티티를 삭제하려면 삭제 대상 엔티티를 조회하고 엔티티 매니저에 삭제 대상 엔티티를 넘겨주면 해당 엔티티를
삭제한다. 엔티티 등록과 동일하게 삭제 쿼리를 쓰기 지연 SQL 저장소에 등록한 뒤 트랜잭션을 커밋해서 플러시를
호출하면 DB에 삭제쿼리를 전달한다.&lt;/p&gt;
&lt;h2 id=&quot;4-플러시&quot; md-pos=&quot;4467-4473&quot;&gt;&lt;a href=&quot;#4-플러시&quot; name=&quot;4-플러시&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4. 플러시&lt;/h2&gt;
&lt;p md-pos=&quot;4475-4540&quot;&gt;&lt;strong md-pos=&quot;4477-4511&quot;&gt;플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다&lt;/strong&gt; 플러시를 실행하면 아래와 같은 일이 일어난다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;4541-4642&quot;&gt;변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교해서 수정된 엔티티를 찾는다. 수정된
  엔티티는 수정 쿼리를 만들어 쓰기 지연 SQL 저장소에 등록한다.&lt;/li&gt;
  &lt;li md-pos=&quot;4642-4678&quot;&gt;쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p md-pos=&quot;4679-4718&quot;&gt;영속성 컨텍스트를 플러시하는 방법은 아래와 같이 3가지 방법이 있다.&lt;/p&gt;
&lt;h3 id=&quot;41-직접호출&quot; md-pos=&quot;4723-4731&quot;&gt;&lt;a href=&quot;#41-직접호출&quot; name=&quot;41-직접호출&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4.1 직접호출&lt;/h3&gt;
&lt;p md-pos=&quot;4733-4839&quot;&gt;&lt;code md-pos=&quot;4734-4755&quot;&gt;entityManager.flush()&lt;/code&gt;메서드 직접 호출해서 영속성 컨텍스트를 강제로 플러시 한다. 테스트 또는 다른
프레임워크랑 함께 JPA를 사용할 때를 제외하고 거의 쓰이지 않는다.&lt;/p&gt;
&lt;h3 id=&quot;42-트랜잭션-커밋-시-플러시-자동-호출&quot; md-pos=&quot;4844-4867&quot;&gt;&lt;a href=&quot;#42-트랜잭션-커밋-시-플러시-자동-호출&quot; name=&quot;42-트랜잭션-커밋-시-플러시-자동-호출&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4.2 트랜잭션 커밋 시 플러시 자동 호출&lt;/h3&gt;
&lt;p md-pos=&quot;4869-5030&quot;&gt;DB에 변경 내용을 SQL로 전달하지 않고 트랜잭션만 커밋하면 어떤 데이터도 DB 반영되지 않는다. 그래서 트랜잭션을
커밋하기 전에 플러시를 호출해서 영속성 컨텍스트의 변경 내용을 DB에 반영해야 한다. JPA는 이러한 문제를 예방하기
위해 트랜잭션을 커밋할 때 플러시를 자동 호출한다.&lt;/p&gt;
&lt;h3 id=&quot;43-jpql-쿼리-실행시-플러시-자동-호출&quot; md-pos=&quot;5035-5060&quot;&gt;&lt;a href=&quot;#43-jpql-쿼리-실행시-플러시-자동-호출&quot; name=&quot;43-jpql-쿼리-실행시-플러시-자동-호출&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4.3 JPQL 쿼리 실행시 플러시 자동 호출&lt;/h3&gt;
&lt;pre md-pos=&quot;5062-5385&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;5070-5381&quot;&gt;// 객체 memberA, memberB, memberC 생성
// 엔티티 매니저 생성, 트랜잭션 획득 ...

entityManager.persist(memberA); // 등록
entityManager.persist(memberB); // 등록
entityManager.persist(memberC); // 등록

// JPQL 실행
List&amp;lt;Member&amp;gt; members = entityManager.createQuery(&amp;quot;SELECT m FROM Member m&amp;quot;, Member.class).getResultList();

// 트랜잭션 커밋 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;5386-5705&quot;&gt;JPQL이나 Criteria 같은 객체지향 쿼리를 호출할 때도 플러시가 실행된다. &lt;code md-pos=&quot;5433-5442&quot;&gt;persist()&lt;/code&gt;메서드를 호출해서
엔티티 &lt;code md-pos=&quot;5458-5465&quot;&gt;memberA&lt;/code&gt;, &lt;code md-pos=&quot;5469-5476&quot;&gt;memberB&lt;/code&gt;, &lt;code md-pos=&quot;5480-5487&quot;&gt;memberC&lt;/code&gt;를 영속 상태로 만들고, 영속성 컨텍스트에 있지만 아직 DB에는
반영되지 않았다. 이 때 JPQL을 실행하면 SQL로 변환되어 데이터베이스에서 엔티티를 조회한다. 그런데 &lt;code md-pos=&quot;5584-5591&quot;&gt;memberA&lt;/code&gt;,
&lt;code md-pos=&quot;5595-5602&quot;&gt;memberB&lt;/code&gt;, &lt;code md-pos=&quot;5606-5613&quot;&gt;memberC&lt;/code&gt;는 아직 데이터베이스에 없으므로 쿼리 결과로 조회가 되지 않는다. 따라서 쿼리를
실행하기 직전에 영속성 컨텍스트를 플러시해서 변경 내용을 DB에 반영해야만 한다.&lt;/p&gt;
&lt;p md-pos=&quot;5706-5804&quot;&gt;JPA는 이런 문제를 예방하기 위해 JPQL을 실행할 때도 플러시를 자동 호출한다. 그래서 &lt;code md-pos=&quot;5758-5765&quot;&gt;memberA&lt;/code&gt;,
&lt;code md-pos=&quot;5769-5776&quot;&gt;memberB&lt;/code&gt;, &lt;code md-pos=&quot;5780-5787&quot;&gt;memberC&lt;/code&gt;들도 쿼리 결과에 포함된다.&lt;/p&gt;
&lt;p md-pos=&quot;5805-5837&quot;&gt;&lt;code md-pos=&quot;5806-5812&quot;&gt;find()&lt;/code&gt;메서드의 경우는 플러시가 실행되지 않는다.&lt;/p&gt;
&lt;p md-pos=&quot;5838-5908&quot;&gt;플러시는 영속성 컨텍스트에 보관된 엔티티를 지우는 것이 아니라 영속성 컨텍스트의 내용변경을 데이터베이스에
동기화하는 것이다.&lt;/p&gt;
&lt;h2 id=&quot;5-준영속&quot; md-pos=&quot;5912-5918&quot;&gt;&lt;a href=&quot;#5-준영속&quot; name=&quot;5-준영속&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5. 준영속&lt;/h2&gt;
&lt;p md-pos=&quot;5920-6023&quot;&gt;&lt;strong md-pos=&quot;5922-5978&quot;&gt;영속성 컨텍스트가 관리하는 영속상태의 엔티티가 영속성 컨텍스트에서 분리된 것을 준영속 상태라고 한다.&lt;/strong&gt; 준영속
상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.&lt;/p&gt;
&lt;h3 id=&quot;51-엔티티를-준영속-상태로-전환--detach&quot; md-pos=&quot;6028-6058&quot;&gt;&lt;a href=&quot;#51-엔티티를-준영속-상태로-전환--detach&quot; name=&quot;51-엔티티를-준영속-상태로-전환--detach&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.1 엔티티를 준영속 상태로 전환 : detach()&lt;/h3&gt;
&lt;pre md-pos=&quot;6060-6192&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;6068-6188&quot;&gt;// 영속 상태
entityManager.persist(member);

// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
entityManager.detach(member);

// 태랜잭션 커밋 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;6193-6376&quot;&gt;&lt;code md-pos=&quot;6194-6202&quot;&gt;detach()&lt;/code&gt;메서드는 특정 엔티티를 준영속 상태로 만드는데 위의 코드를 보면 먼저 회원 엔티티를 영속화한
다음 &lt;code md-pos=&quot;6259-6267&quot;&gt;detach()&lt;/code&gt;메서드를 호출했다. 영속성 컨텍스트에게 해당 엔티티를 관리하지 말라는 것이다. 이 메서드를
호출하면 1차 캐시, 쓰기 지연 SQL 저장소까지 해당 엔티티를 관리하기 위한 정보가 모두 제거된다.&lt;/p&gt;
&lt;h3 id=&quot;52-영속성-컨텍스트-초기화--clear&quot; md-pos=&quot;6381-6407&quot;&gt;&lt;a href=&quot;#52-영속성-컨텍스트-초기화--clear&quot; name=&quot;52-영속성-컨텍스트-초기화--clear&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.2 영속성 컨텍스트 초기화 : clear()&lt;/h3&gt;
&lt;pre md-pos=&quot;6409-6602&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;6417-6598&quot;&gt;// 엔티티 조회, 영속 상태
Member member = entityManager.find(Member.class, &amp;quot;id001&amp;quot;);

// 영속성 컨텍스트 초기화
entityManager.clear();

// 준영속 상태
member.setAge(&amp;quot;28&amp;quot;); // 변경 감지는 독장 하지 않기 때문에 변경되지 않는다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;6603-6694&quot;&gt;&lt;code md-pos=&quot;6604-6611&quot;&gt;clear()&lt;/code&gt;메서드는 영속성 컨텍스트를 초기화해서 해당 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만든다.
영속성 컨텍스트를 제거하고 새로 만든것과 같다.&lt;/p&gt;
&lt;h3 id=&quot;53-영속성-컨텍스트-종료--close&quot; md-pos=&quot;6699-6724&quot;&gt;&lt;a href=&quot;#53-영속성-컨텍스트-종료--close&quot; name=&quot;53-영속성-컨텍스트-종료--close&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.3 영속성 컨텍스트 종료 : close()&lt;/h3&gt;
&lt;pre md-pos=&quot;6726-6992&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;6734-6988&quot;&gt;// 엔티티 매니저 생성, 트랜잭션 획득 ...

transaction.begin(); // 트랜잭션 시작

Member memberA = entityManager.find(Member.class, &amp;quot;id001&amp;quot;);
Member memberB = entityManager.find(Member.class, &amp;quot;id002&amp;quot;);

transaction.commit(); // 트랜잭션 커밋

entityManager.close(); // 영속성 컨텍스트 닫기
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;6993-7053&quot;&gt;영속성 컨텍스트트 종료하면 해당 영속성 컨텍스트가 관리하던 영속 상태의 엔티티가 모두 준영속 상태가 된다.&lt;/p&gt;
&lt;h3 id=&quot;54-준영속-상태의-특징&quot; md-pos=&quot;7058-7072&quot;&gt;&lt;a href=&quot;#54-준영속-상태의-특징&quot; name=&quot;54-준영속-상태의-특징&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.4 준영속 상태의 특징&lt;/h3&gt;
&lt;p md-pos=&quot;7074-7099&quot;&gt;준영속 상태의 엔티티의 특징은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;7100-7153&quot;&gt;거의 비영속 상태에 가깝기 때문에 영속성 컨텍스트가 제공하는 어떤 기능도 동작하지 않는다.&lt;/li&gt;
  &lt;li md-pos=&quot;7153-7210&quot;&gt;비영속 상태는 식별값이 없지만 준영속 상태는 이미 영속 상태였기 때문에 식별자 값을 가지고 있다.&lt;/li&gt;
  &lt;li md-pos=&quot;7210-7235&quot;&gt;지연로딩을 할 수 없다.(추후 정리예정)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;55-병합--merge&quot; md-pos=&quot;7240-7256&quot;&gt;&lt;a href=&quot;#55-병합--merge&quot; name=&quot;55-병합--merge&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5.5 병합 : merge()&lt;/h3&gt;
&lt;p md-pos=&quot;7258-7359&quot;&gt;준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 병합을 사용하면 된다. &lt;code md-pos=&quot;7301-7308&quot;&gt;merge()&lt;/code&gt;메서드는 준영속 상태의
엔티티를 받아서 그 정보로 새로운 영속 상태의 엔티티를 반환한다.&lt;/p&gt;
&lt;pre md-pos=&quot;7360-9405&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;7368-9401&quot;&gt;public class ExamMergeMain {

    // 엔티티 매니저 팩토리 생성
    private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(&amp;quot;jpa03&amp;quot;);

    public static void main(String[] args) {

        // 회원 엔티티 생성 --&amp;gt; 준영속 상태
        Member member = createMember(&amp;quot;id001&amp;quot;, &amp;quot;doubles&amp;quot;, 20);

        // 준영속 상태 --&amp;gt; 회원 정보 변경 : 변경이 이루어지지 않음
        member.setUsername(&amp;quot;더블에스&amp;quot;);

        // 회원 엔티티 병합
        mergeMember(member);
    }

    // 회원 엔티티 생성 --&amp;gt; 영속성 컨텍스트 종료
    private static Member createMember(String id, String username, int age) {

        // 엔티티 매니저 생성
        EntityManager entityManager1 = entityManagerFactory.createEntityManager();

        // 트랜잭션 획득
        EntityTransaction transaction1 = entityManager1.getTransaction();

        transaction1.begin();   // 트랜잭션 시작

        // 회원 객체 생성
        Member member = new Member();
        member.setId(id);
        member.setUsername(username);
        member.setAge(age);

        // 회원 엔티티 등록
        entityManager1.persist(member);

        transaction1.commit();  // 트랜잭션 커밋

        // 영속성 컨텍스트 종료 ---&amp;gt; 회원 엔티티 준영속 상태로 변경됨
        entityManager1.close();

        return member;
    }

    // 병합
    private static void mergeMember(Member member) {

        // 엔티티 매니저 생성
        EntityManager entityManager2 = entityManagerFactory.createEntityManager();

        // 트랜잭션 획득
        EntityTransaction transaction2 = entityManager2.getTransaction();

        transaction2.begin(); // 트랜잭션 시작

        // 회원 엔티티 병합 ---&amp;gt; 회원 엔티티 변경 감지 DB 반영
        Member mergeMember = entityManager2.merge(member);

        transaction2.commit(); // 트랜잭션 커밋

        System.out.println(&amp;quot;member = &amp;quot; + member.getUsername()); // 준영속 상태

        System.out.println(&amp;quot;mergeMember = &amp;quot; + mergeMember.getUsername()); // 영속 상태

        System.out.println(&amp;quot;entityManager2 contains member = &amp;quot; + entityManager2.contains(member));

        System.out.println(&amp;quot;entityManager2 contains mergeMember = &amp;quot; + entityManager2.contains(mergeMember));

        entityManager2.close();
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;9406-9472&quot;&gt;위의 코드는 준영속 상태의 엔티티가 어떻게 영속상태로 변경되는지 알아보기 위해 작성된 것으로 큰 흐름은 아래와 같다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;9473-9547&quot;&gt;&lt;code md-pos=&quot;9477-9491&quot;&gt;createMember()&lt;/code&gt;메서드에서 회원 엔티티를 생성하고, 등록한 뒤에 영속성 컨텍스트를 종료시켜 준영속 상태로 만든다.&lt;/li&gt;
  &lt;li md-pos=&quot;9547-9587&quot;&gt;준영속 상태의 회원 엔티티를 변경하면 변경사항이 적용되지 않는다.&lt;/li&gt;
  &lt;li md-pos=&quot;9587-9647&quot;&gt;&lt;code md-pos=&quot;9591-9604&quot;&gt;mergeMember()&lt;/code&gt;매서드에서 회원 엔티티를 병합하고, 변경사항을 감지하여 DB에 동기화한다.&lt;/li&gt;
  &lt;li md-pos=&quot;9647-9721&quot;&gt;반환된 &lt;code md-pos=&quot;9655-9666&quot;&gt;mergeMember&lt;/code&gt;와 &lt;code md-pos=&quot;9670-9676&quot;&gt;member&lt;/code&gt;가 영속성 컨텍스트에 존재하는지 &lt;code md-pos=&quot;9696-9706&quot;&gt;contains()&lt;/code&gt;메서드를 통해 확인한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p md-pos=&quot;9722-9762&quot;&gt;위 코드를 실행하고 나면 콘솔에서 아래와 같이 결과를 확인할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;9763-10453&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;9774-10449&quot;&gt;Hibernate:
    /* insert com.doubles.jpa03.Member
        */ insert
        into
            MEMBER
            (age, NAME, ID)
        values
            (?, ?, ?)
Hibernate:
    /* load com.doubles.jpa03.Member */ select
        member0_.ID as ID1_0_0_,
        member0_.age as age2_0_0_,
        member0_.NAME as NAME3_0_0_
    from
        MEMBER member0_
    where
        member0_.ID=?
Hibernate:
    /* update
        com.doubles.jpa03.Member */ update
            MEMBER
        set
            age=?,
            NAME=?
        where
            ID=?
member = 더블에스
mergeMember = 더블에스
entityManager2 contains member = false
entityManager2 contains mergeMember = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;10454-10658&quot;&gt;콘솔 화면을 통해 확인할 수 있는 것은 &lt;code md-pos=&quot;10477-10484&quot;&gt;merge()&lt;/code&gt;메서드를 통해 반환 받은 &lt;code md-pos=&quot;10500-10511&quot;&gt;mergeMember&lt;/code&gt;와 &lt;code md-pos=&quot;10515-10521&quot;&gt;member&lt;/code&gt;는
다른 인스턴스라는 것을 알 수 있고, &lt;code md-pos=&quot;10546-10557&quot;&gt;mergeMember&lt;/code&gt;는 영속상태이고, &lt;code md-pos=&quot;10569-10575&quot;&gt;member&lt;/code&gt;는 여전히 준영속 상태라는 것을
알 수 있다. 이렇게 준영속 엔티티를 참조하던 변수는 영속 엔티티를 참조하도록 변경하는 것이 안전하고 바람직하다.&lt;/p&gt;
&lt;pre md-pos=&quot;10659-10779&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;10667-10775&quot;&gt;//Member mergeMember = entityManager2.merge(member); 코드 변경
member = entityManager2.merge(member); // 참조를 변경
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;10780-10819&quot;&gt;&lt;code md-pos=&quot;10781-10788&quot;&gt;merge()&lt;/code&gt;메서드는 비영속 엔티티도 영속상태로 만들 수도 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;10820-10930&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;10828-10926&quot;&gt;Member member = new Member(); // 비영속 상태
Member newMember = entityManager.merge(member); // 엔티티 병합
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;10931-11029&quot;&gt;병합은 파라미터로 넘어온 엔티티의 식별자로 영속성 컨텍스트를 조회하고 없을 경우 DB를 조회한다. 만약 DB에도
존재하지 않는다면 새로운 엔티티를 생성해서 병합을 하게 된다.&lt;/p&gt;
&lt;p md-pos=&quot;11030-11092&quot;&gt;병합은 준영속, 비영속을 가리지 않고 식별자로 조회가 가능하면 불러와 병합하고 없다면 새로 생성해서 병합한다.&lt;/p&gt;
&lt;h2 id=&quot;6-summery--conclusion&quot; md-pos=&quot;11097-11120&quot;&gt;&lt;a href=&quot;#6-summery--conclusion&quot; name=&quot;6-summery--conclusion&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6. Summery / Conclusion&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;11122-11151&quot;&gt;영속성 컨텍스트는 엔티티를 영구히 저장하는 환경&lt;/li&gt;
  &lt;li md-pos=&quot;11151-11266&quot;&gt;엔티티 생명주기
    &lt;ul&gt;
      &lt;li md-pos=&quot;11164-11178&quot;&gt;비영속 : 관계 없음&lt;/li&gt;
      &lt;li md-pos=&quot;11180-11208&quot;&gt;영속  : 저장된 상태, &lt;code md-pos=&quot;11197-11206&quot;&gt;persist()&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;11210-11237&quot;&gt;준영속 : 분리된 상태, &lt;code md-pos=&quot;11227-11235&quot;&gt;detach()&lt;/code&gt;&lt;/li&gt;
      &lt;li md-pos=&quot;11239-11266&quot;&gt;삭제  : 삭제된 상태, &lt;code md-pos=&quot;11256-11264&quot;&gt;remove()&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;11266-11535&quot;&gt;영속성 컨텍스트의 장점과 특징
    &lt;ul&gt;
      &lt;li md-pos=&quot;11287-11342&quot;&gt;1차캐시 : 영속성 컨텍스트에 존재하는 일종의 가상DB, Map처럼 key와 value를 가짐&lt;/li&gt;
      &lt;li md-pos=&quot;11344-11401&quot;&gt;동일성 보장 : 같은 엔티티를 조회할 경우, 컨텍스트에 존재하는 엔티티를 바로 반환, 속도에 이점&lt;/li&gt;
      &lt;li md-pos=&quot;11403-11448&quot;&gt;쓰기지연 : SQL 내부저장소에 모아두었다가 트랜잭션 커밋할 때 DB에 전달&lt;/li&gt;
      &lt;li md-pos=&quot;11450-11524&quot;&gt;변경감지 : 엔티티의 변경사항을 스냅샷을 통해 감지하고, DB에 동기화, UPDATE SQL은 모든필드를 수정하는 SQL을 사용&lt;/li&gt;
      &lt;li md-pos=&quot;11526-11535&quot;&gt;지연로딩 :&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;11535-11584&quot;&gt;플러시 : 트랜잭션 커밋할 때 영속성 컨텍스트가 플러시되고 DB에 변경사항을 동기화&lt;/li&gt;
  &lt;li md-pos=&quot;11584-11623&quot;&gt;준영속 상태에서는 영속성 컨텍스트가 제공하는 기능을 사용하지 못함&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <category>JPA</category>
      <category>detach()</category>
      <category>JPA</category>
      <category>merge()</category>
      <category>remove()</category>
      <category>영속성 컨텍스트</category>
      <author>더블에스님</author>
      <guid isPermaLink="true">https://doublesprogramming.tistory.com/259</guid>
      <comments>https://doublesprogramming.tistory.com/259#entry259comment</comments>
      <pubDate>Thu, 14 Mar 2019 23:11:55 +0900</pubDate>
    </item>
    <item>
      <title>JPA 프로젝트 생성 및 세팅</title>
      <link>https://doublesprogramming.tistory.com/258</link>
      <description>&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_layout-fx.css&quot;&gt;
&lt;style&gt;
.container { width: 100%; }
.wiki-container { width: 100%; }
.wiki-body { width: 100%; }
&lt;/style&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_default-fx.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism-default.css&quot;&gt;
&lt;title&gt;ch02-jpa-start.md&lt;/title&gt;
&lt;script src=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism.pack.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;blockquote&gt;
  &lt;p md-pos=&quot;2-161&quot;&gt;본 글은 &lt;a href=&quot;https://book.naver.com/bookdb/book_detail.nhn?bid=9252528&quot; md-pos=&quot;7-87&quot;&gt;자바 ORM 표준 JPA 프로그래밍&lt;/a&gt;를 읽고 개인적으로
  학습한 내용 복습하기 위해 작성된 글로 내용상 오류가 있을 수 있습니다. 오류가 있다면 지적 부탁 드리겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;jpa-시작&quot; md-pos=&quot;165-171&quot;&gt;&lt;a href=&quot;#jpa-시작&quot; name=&quot;jpa-시작&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;JPA 시작&lt;/h1&gt;
&lt;h2 id=&quot;1-jpa-프로젝트-생성-및-설정&quot; md-pos=&quot;176-195&quot;&gt;&lt;a href=&quot;#1-jpa-프로젝트-생성-및-설정&quot; name=&quot;1-jpa-프로젝트-생성-및-설정&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1. JPA 프로젝트 생성 및 설정&lt;/h2&gt;
&lt;h3 id=&quot;11-프로젝트-생성&quot; md-pos=&quot;201-212&quot;&gt;&lt;a href=&quot;#11-프로젝트-생성&quot; name=&quot;11-프로젝트-생성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.1 프로젝트 생성&lt;/h3&gt;
&lt;p md-pos=&quot;214-267&quot;&gt;IntelliJ에서 maven 프로젝트를 생성하고 &lt;code md-pos=&quot;243-250&quot;&gt;pom.xml&lt;/code&gt;을 아래와 같이 작성해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;268-1147&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-xml&quot; md-pos=&quot;275-1143&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;project xmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot;
         xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
         xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

    &amp;lt;groupId&amp;gt;com.doubles&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jpa02&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;!--JPA, 하이버네이트--&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.hibernate&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;hibernate-entitymanager&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;4.3.10.Final&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;!--h2 DB--&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;com.h2database&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;h2&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.4.187&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&amp;lt;/project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;1148-1171&quot;&gt;JPA, 하이버네이트 라이브러리 추가&lt;/li&gt;
  &lt;li md-pos=&quot;1171-1192&quot;&gt;H2 데이터베이스 라이브러리 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;12-h2-데이터베이스-설치-및-테이블-생성&quot; md-pos=&quot;1197-1222&quot;&gt;&lt;a href=&quot;#12-h2-데이터베이스-설치-및-테이블-생성&quot; name=&quot;12-h2-데이터베이스-설치-및-테이블-생성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.2 H2 데이터베이스 설치 및 테이블 생성&lt;/h3&gt;
&lt;p md-pos=&quot;1224-1327&quot;&gt;&lt;a href=&quot;http://www.h2database.com/h2-2014-04-05.zip&quot; md-pos=&quot;1224-1280&quot;&gt;H2 데이터베이스&lt;/a&gt;를 다운받고, 압축을 해제한 뒤
&lt;code md-pos=&quot;1299-1305&quot;&gt;h2/bin&lt;/code&gt; 경로에서 아래와 같이 실행 시킨다.&lt;/p&gt;
&lt;pre md-pos=&quot;1328-1362&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-shell&quot; md-pos=&quot;1337-1358&quot;&gt;java -jar h2[버전].jar
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;1363-1436&quot;&gt;그리고 &lt;code md-pos=&quot;1368-1390&quot;&gt;http://localhost:8082/&lt;/code&gt;로 접속하여 h2 로그인 화면이 나오면 아래의 정보를 입력하고 연결을
진행한다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;1436-1463&quot;&gt;드라이버 클래스 : org.h2.driver&lt;/li&gt;
  &lt;li md-pos=&quot;1463-1507&quot;&gt;JDBC URL : jdbc:h2:&lt;a md-pos=&quot;1484-1506&quot; href=&quot;tcp://localhost/~/test&quot;&gt;tcp://localhost/~/test&lt;/a&gt;&lt;/li&gt;
  &lt;li md-pos=&quot;1507-1519&quot;&gt;사용자명 : sa&lt;/li&gt;
  &lt;li md-pos=&quot;1519-1531&quot;&gt;비밀번호 : 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;1532-1557&quot;&gt;그리고 예제에 필요한 테이블 생성을 해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;1558-1685&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-sql&quot; md-pos=&quot;1565-1681&quot;&gt;CREATE TABLE MEMBER (
  ID VARCHAR(255) NOT NULL,
  NAME VARCHAR(255),
  AGE INTEGER NOT NULL,
  PRIMARY KEY (ID)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;13-persistencexml-설정&quot; md-pos=&quot;1690-1712&quot;&gt;&lt;a href=&quot;#13-persistencexml-설정&quot; name=&quot;13-persistencexml-설정&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.3 persistence.xml 설정&lt;/h3&gt;
&lt;p md-pos=&quot;1714-1816&quot;&gt;JPA는 &lt;code md-pos=&quot;1720-1735&quot;&gt;persistence.xml&lt;/code&gt;을 사용해 필요한 정보를 관리한다. 이 설정 파일이 &lt;code md-pos=&quot;1766-1790&quot;&gt;META-INF/persistence.xml&lt;/code&gt; 경로에 있으면 별도의 설정 없이 인식한다.&lt;/p&gt;
&lt;pre md-pos=&quot;1817-3812&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-xml&quot; md-pos=&quot;1824-3808&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;!--JPA는 persistence.xml을 사용하여 필요한 설정 정보를 관리--&amp;gt;
&amp;lt;persistence xmlns=&amp;quot;http://xmlns.jcp.org/xml/ns/persistence&amp;quot; version=&amp;quot;2.1&amp;quot;&amp;gt; &amp;lt;!-- 버전 명시 --&amp;gt;
    &amp;lt;persistence-unit name=&amp;quot;jpa02&amp;quot;&amp;gt; &amp;lt;!-- 데이터베이스당 하나의 영속성 유닛을 등록하기 위해 고유한 이름 부여 --&amp;gt;
        &amp;lt;properties&amp;gt;

            &amp;lt;!-- 필수 속성 --&amp;gt;
            &amp;lt;!--javax.persistence로 시작하는 속성은 JPA 표준속성으로 특정 구현체에 종속되지 X--&amp;gt;
            &amp;lt;!--JPA 표준 속성--&amp;gt;
            &amp;lt;property name=&amp;quot;javax.persistence.jdbc.driver&amp;quot; value=&amp;quot;org.h2.Driver&amp;quot;/&amp;gt; &amp;lt;!--JDBC 드라이버--&amp;gt;
            &amp;lt;property name=&amp;quot;javax.persistence.jdbc.user&amp;quot; value=&amp;quot;sa&amp;quot;/&amp;gt; &amp;lt;!--데이터베이스 접속 id--&amp;gt;
            &amp;lt;property name=&amp;quot;javax.persistence.jdbc.password&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt; &amp;lt;!--데이터베이스 접속 pw--&amp;gt;
            &amp;lt;property name=&amp;quot;javax.persistence.jdbc.url&amp;quot; value=&amp;quot;jdbc:h2:tcp://localhost/~/test&amp;quot;/&amp;gt; &amp;lt;!--데이터베이스 접속 URL--&amp;gt;

            &amp;lt;!--하이버네이트 속성--&amp;gt;
            &amp;lt;!--hibernate로 시작하는 속성은 하이버네이트 전용 속성으므로 하이버네이트에서만 사용가능--&amp;gt;
            &amp;lt;!--데이터베이스 방언 : 데이터베이스별로 SQL문법과 함수가 조금씩 다른 것을 의미--&amp;gt;
            &amp;lt;!--H2 데이터베이스 방언--&amp;gt;
            &amp;lt;property name=&amp;quot;hibernate.dialect&amp;quot; value=&amp;quot;org.hibernate.dialect.H2Dialect&amp;quot; /&amp;gt;

            &amp;lt;!--
            오라클 10g 데이터베이스 방언
            &amp;lt;property name=&amp;quot;hibernate.dialect&amp;quot; value=&amp;quot;org.hibernate.dialect.Oracle10gDialect&amp;quot; /&amp;gt;
            --&amp;gt;

            &amp;lt;!--
            Mysql 데이터베이스 방언
            &amp;lt;property name=&amp;quot;hibernate.dialect&amp;quot; value=&amp;quot;org.hibernate.dialect.MySQL5InnoDBDialect&amp;quot; /&amp;gt;
            --&amp;gt;

            &amp;lt;!-- 옵션 --&amp;gt;
            &amp;lt;property name=&amp;quot;hibernate.show_sql&amp;quot; value=&amp;quot;true&amp;quot; /&amp;gt; &amp;lt;!--하이버네이트가 실행한 SQL을 출력--&amp;gt;
            &amp;lt;property name=&amp;quot;hibernate.format_sql&amp;quot; value=&amp;quot;true&amp;quot; /&amp;gt; &amp;lt;!--하이버네이트가 실행한 SQL을 출력할 때 정렬--&amp;gt;
            &amp;lt;property name=&amp;quot;hibernate.use_sql_comments&amp;quot; value=&amp;quot;true&amp;quot; /&amp;gt; &amp;lt;!--쿼리를 출력할 때 주석도 함께--&amp;gt;
            &amp;lt;property name=&amp;quot;hibernate.id.new_generator_mappings&amp;quot; value=&amp;quot;true&amp;quot; /&amp;gt; &amp;lt;!--JPA표준에 맞춘 새로운 키 생성 전략 사용--&amp;gt;

            &amp;lt;!--&amp;lt;property name=&amp;quot;hibernate.hbm2ddl.auto&amp;quot; value=&amp;quot;create&amp;quot; /&amp;gt;--&amp;gt;
        &amp;lt;/properties&amp;gt;
    &amp;lt;/persistence-unit&amp;gt;
&amp;lt;/persistence&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;14-프로젝트-구조&quot; md-pos=&quot;3817-3828&quot;&gt;&lt;a href=&quot;#14-프로젝트-구조&quot; name=&quot;14-프로젝트-구조&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1.4 프로젝트 구조&lt;/h3&gt;
&lt;p md-pos=&quot;3830-3897&quot;&gt;위와 같이 설정을 마무리하고 기본패키지 하위에 앞으로 작성할 클래스를 추가하면 아래와 같이 프로젝트 구조가
이루어진다.&lt;/p&gt;
&lt;pre md-pos=&quot;3898-4108&quot; class=&quot;line-numbers&quot;&gt;&lt;code md-pos=&quot;3902-4104&quot;&gt;src/main
├── java
|     └── 기본패키지
|             ├── JpaMain.java (실행클래스)
|             └── Member.java (회원 엔티티)
├── resources
|       └── META-INF
|               └── persistence.xml (JPA 설정정보)
pom.xml
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-객체-매핑&quot; md-pos=&quot;4112-4120&quot;&gt;&lt;a href=&quot;#2-객체-매핑&quot; name=&quot;2-객체-매핑&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2. 객체 매핑&lt;/h2&gt;
&lt;p md-pos=&quot;4122-4157&quot;&gt;애플리케이션에서 사용할 회원 클래스를 아래와 같이 작성해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;4158-4579&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;4166-4575&quot;&gt;// Member 클래스
@Entity // 클래스와 테이블을 매핑하는 것을 알려준다. 엔티티 클래스라 한다.
@Table(name = &amp;quot;MEMBER&amp;quot;) // 매핑할 테이블 정보 명시, 생력할 경우 클래스명으로 테이블 이름 매핑
public class Member {

    @Id // 기본키 매핑, 식별자 필드
    @Column(name = &amp;quot;ID&amp;quot;) // 필드를 컬럼에 매핑
    private String id;

    @Column(name = &amp;quot;NAME&amp;quot;)
    private String username;

    private Integer age; // 매핑 정보가 없을 경우 필드명이 컬럼명으로 매핑 , 대소문자를 구분하는 DB일 경우 명시해줘야한다.

    // getter, setter 생략
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;4580-4608&quot;&gt;기본적인 매핑 애너테이션은 추가적으로 정리할 예정&lt;/p&gt;
&lt;h2 id=&quot;3-애플리케이션-개발&quot; md-pos=&quot;4612-4624&quot;&gt;&lt;a href=&quot;#3-애플리케이션-개발&quot; name=&quot;3-애플리케이션-개발&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3. 애플리케이션 개발&lt;/h2&gt;
&lt;p md-pos=&quot;4626-4655&quot;&gt;JPA 애플리케이션을 실행하는 코드는 아래와 같다.&lt;/p&gt;
&lt;pre md-pos=&quot;4656-6317&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;4664-6313&quot;&gt;// JpaMain 클래스
public class JpaMain {
    public static void main(String[] args) {

        // 1. 엔티티 매나저 팩토리 생성
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(&amp;quot;jpa02&amp;quot;);

        // 2. 엔티티 매나저 생성
        EntityManager entityManager = entityManagerFactory.createEntityManager();

        // 3. 트랜잭션 획득
        EntityTransaction entityTransaction = entityManager.getTransaction();

        try {
            entityTransaction.begin();  // 4. 트랜잭션 시작
            logic(entityManager);       // 5. 비지니스 로직 수행
            entityTransaction.commit(); // 6. 트랜잭션 커밋
        } catch (Exception e) {
            entityTransaction.rollback();   // 6. 트랜잭션 롤백
        } finally {
            entityManager.close();      // 7. 엔티티 매니저 종료
        }
        entityManagerFactory.close();   // 7. 엔티티 매니저 팩토리 종료
    }

    // 비지니스 로직
    private static void logic(EntityManager entityManager) {

        // 회원 객체 생성
        String id = &amp;quot;id01&amp;quot;;
        Member member = new Member();
        member.setId(id);
        member.setUsername(&amp;quot;doubles&amp;quot;);
        member.setAge(20);

        // 등록
        entityManager.persist(member);

        // 수정
        member.setAge(25);

        // 조회 : 하나의 회원
        Member findMember = entityManager.find(Member.class, id);
        System.out.println(&amp;quot;findMember : &amp;quot; + findMember.getUsername() + &amp;quot;, &amp;quot; + findMember.getAge());

        // 조회 : 목록
        List&amp;lt;Member&amp;gt; members = entityManager.createQuery(&amp;quot;SELECT m FROM Member m&amp;quot;, Member.class).getResultList();
        System.out.println(&amp;quot;members.size = &amp;quot; + members.size());

        // 삭제
        entityManager.remove(member);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;6318-6394&quot;&gt;위의 코드는 엔티티 &lt;strong md-pos=&quot;6331-6355&quot;&gt;매니저 설정, 트랜잭션 관리, 비지니스 로직&lt;/strong&gt; 으로 크게 3부분으로 나누어져 있다. 이 세부 내용을 살펴보자.&lt;/p&gt;
&lt;h3 id=&quot;31-엔티티-매니저-설정&quot; md-pos=&quot;6399-6413&quot;&gt;&lt;a href=&quot;#31-엔티티-매니저-설정&quot; name=&quot;31-엔티티-매니저-설정&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.1 엔티티 매니저 설정&lt;/h3&gt;
&lt;p md-pos=&quot;6415-6449&quot;&gt;엔티티 매니저의 생성과정은 아래와 같은 순서로 진행이 된다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li md-pos=&quot;6450-6490&quot;&gt;설정정보 조회(&lt;code md-pos=&quot;6462-6487&quot;&gt;/META-INF/persistence.xml&lt;/code&gt;)&lt;/li&gt;
  &lt;li md-pos=&quot;6490-6508&quot;&gt;엔티티 매니저 팩토리 생성&lt;/li&gt;
  &lt;li md-pos=&quot;6508-6522&quot;&gt;엔티티 매니저 생성&lt;/li&gt;
  &lt;li md-pos=&quot;6522-6528&quot;&gt;종료&lt;/li&gt;
&lt;/ol&gt;
&lt;p md-pos=&quot;6529-6556&quot;&gt;위의 과정에서 주의해야할 사항들은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;6556-6604&quot;&gt;엔티티 매니저 팩토리는 애플리케이션 전체에 한번만 생성하고 공유해서 사용해야한다.&lt;/li&gt;
  &lt;li md-pos=&quot;6604-6663&quot;&gt;엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드가 공유하거나 재사용해서는 안된다.&lt;/li&gt;
  &lt;li md-pos=&quot;6663-6694&quot;&gt;사용이 끝난 엔티티 매니저는 반드시 종료해야 한다.&lt;/li&gt;
  &lt;li md-pos=&quot;6694-6732&quot;&gt;애플리케이션을 종료할 때 엔티티 매니저 팩토리도 종료해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;32-트랜잭션-관리&quot; md-pos=&quot;6737-6748&quot;&gt;&lt;a href=&quot;#32-트랜잭션-관리&quot; name=&quot;32-트랜잭션-관리&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.2 트랜잭션 관리&lt;/h3&gt;
&lt;p md-pos=&quot;6750-6861&quot;&gt;JPA를 사용하면 항상 트랜잭션 안에서 데이터를 변경해야 한다. 트랜잭션 없이 데이터를 변경할 경우 항상 예외가
발생한다. 트랜잭션을 시작하려면 엔티티 매니저에서 트랜잭션 API를 받아와야만 한다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;6862-6898&quot;&gt;비지니스 로직이 정상 작동하면 트랜잭션을 커밋(commit)&lt;/li&gt;
  &lt;li md-pos=&quot;6898-6922&quot;&gt;예외가 발생하면 롤백(rollback)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;33-비지니스-로직&quot; md-pos=&quot;6927-6938&quot;&gt;&lt;a href=&quot;#33-비지니스-로직&quot; name=&quot;33-비지니스-로직&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.3 비지니스 로직&lt;/h3&gt;
&lt;p md-pos=&quot;6940-7016&quot;&gt;위의 코드에서 비지니스 로직을 보면 회원 엔티티를 하나 생성하고 엔티티 매니저를 통해 데이터베이스에 등록,
수정, 삭제, 조회를 한다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;7017-7080&quot;&gt;
    &lt;p md-pos=&quot;7019-7022&quot;&gt;등록&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;7024-7080&quot;&gt;엔티티를 저장하려면 엔티티 매니저의 &lt;code md-pos=&quot;7047-7056&quot;&gt;persist()&lt;/code&gt;메서드에 저장할 엔티티를 넘겨주면 된다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;7081-7164&quot;&gt;
    &lt;p md-pos=&quot;7083-7086&quot;&gt;수정&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;7088-7117&quot;&gt;JPA는 별도의 수정 메서드가 존재하지 않는다.&lt;/li&gt;
      &lt;li md-pos=&quot;7119-7164&quot;&gt;단순히 엔티티의 값만 변경하면 JPA는 어떤 엔티티가 변경되었는지 추척한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;7165-7227&quot;&gt;
    &lt;p md-pos=&quot;7167-7170&quot;&gt;삭제&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;7172-7227&quot;&gt;엔티티를 삭제하려면 엔티티 매니저의 &lt;code md-pos=&quot;7195-7203&quot;&gt;remove()&lt;/code&gt;메서드에 삭제할 엔티티를 넘겨주면 된다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;7228-7350&quot;&gt;
    &lt;p md-pos=&quot;7230-7243&quot;&gt;조회 : 하나의 엔티티&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;7245-7320&quot;&gt;&lt;code md-pos=&quot;7248-7254&quot;&gt;find()&lt;/code&gt;메서드는 조회할 엔티티 타입과 &lt;code md-pos=&quot;7273-7276&quot;&gt;@Id&lt;/code&gt;로 DB 테이블의 기본키와 매핑한 식별자 값으로 엔티티
      하나를 조회한다.&lt;/li&gt;
      &lt;li md-pos=&quot;7322-7350&quot;&gt;조회한 결과 값으로 엔티티를 생성해 반환한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li md-pos=&quot;7351-7402&quot;&gt;
    &lt;p md-pos=&quot;7353-7365&quot;&gt;조회 : 엔티티 목록&lt;/p&gt;
    &lt;ul&gt;
      &lt;li md-pos=&quot;7367-7402&quot;&gt;하나 이상의 회원 목록을 조회할 경우 JPQL를 사용한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p md-pos=&quot;7403-7450&quot;&gt;그렇다면 JPQL에 대해 간략하게 알아보자. (JPQL은 추후에 따로 정리할 예정)&lt;/p&gt;
&lt;p md-pos=&quot;7451-7602&quot;&gt;JPA는 엔티티 객체를 중심으로 개발하므로 검색할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색해야 한다.
그런데 테이블이 아닌 엔티티 객체를 대상으로 검색하려면 데이터베이스의 모든 데이터를 불러와 엔티티 객체로
변경한 다음 검색을 해야하는데 이는 사실상 불가능하다.&lt;/p&gt;
&lt;p md-pos=&quot;7603-7720&quot;&gt;그래서 필요한 데이터만 데이터베이스에 불러오려면 검색조건이 포함된 SQL을 사용해야 한다. JPA는 이러한 문제를 JPQL(Java Persistence Query Language)이라는 쿼리언어로 해결한다.&lt;/p&gt;
&lt;p md-pos=&quot;7721-7822&quot;&gt;JPA는 SQL을 추상화한 JPQL을 제공하는데 SQL과 문법이 거의 유사해서 SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 등을 사용할 수 있다.&lt;/p&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;7823-7857&quot;&gt;JPQL : 엔티티 객체(클래스, 필드)를 대상으로 쿼리&lt;/li&gt;
  &lt;li md-pos=&quot;7857-7885&quot;&gt;SQL : 데이터베이스 테이블을 대상으로 쿼리&lt;/li&gt;
&lt;/ul&gt;
&lt;pre md-pos=&quot;7886-7920&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-sql&quot; md-pos=&quot;7893-7916&quot;&gt;SELECT m FROM Member m
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;7921-8018&quot;&gt;위의 &lt;code md-pos=&quot;7925-7931&quot;&gt;Member&lt;/code&gt;는 데이터베이스의 MEMBER 테이블이 아니라 엔티티의 &lt;code md-pos=&quot;7964-7970&quot;&gt;Member&lt;/code&gt;이다. JPQL은 데이터베이스 테이블의 &lt;code md-pos=&quot;7994-8000&quot;&gt;MEMBER&lt;/code&gt;를 전혀 알지 못하는 것이다.&lt;/p&gt;
&lt;p md-pos=&quot;8019-8137&quot;&gt;JPQL을 사용하려면 &lt;code md-pos=&quot;8032-8075&quot;&gt;entityManager.createQuery(JPQL, returnType)&lt;/code&gt;메서드를 실행해서 쿼리 객체를 생성한 후에 쿼리객체의 &lt;code md-pos=&quot;8107-8122&quot;&gt;getResultList()&lt;/code&gt;메서드를 호출하면 된다.&lt;/p&gt;
&lt;h3 id=&quot;34-애플리케이션-실행-결과&quot; md-pos=&quot;8142-8158&quot;&gt;&lt;a href=&quot;#34-애플리케이션-실행-결과&quot; name=&quot;34-애플리케이션-실행-결과&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3.4 애플리케이션 실행 결과&lt;/h3&gt;
&lt;pre md-pos=&quot;8160-8895&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-console&quot; md-pos=&quot;8171-8891&quot;&gt;findMember : doubles, 25
Hibernate:
    /* insert com.doubles.jpa02.Member
        */ insert
        into
            MEMBER
            (age, NAME, ID)
        values
            (?, ?, ?)
Hibernate:
    /* update
        com.doubles.jpa02.Member */ update
            MEMBER
        set
            age=?,
            NAME=?
        where
            ID=?
Hibernate:
    /* SELECT
        m
    FROM
        Member m */ select
            member0_.ID as ID1_0_,
            member0_.age as age2_0_,
            member0_.NAME as NAME3_0_
        from
            MEMBER member0_
members.size = 1
Hibernate:
    /* delete com.doubles.jpa02.Member */ delete
        from
            MEMBER
        where
            ID=?
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;8896-8934&quot;&gt;위와 같이 콘솔에 수행한 SQL들이 출력되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;4-summery--conculsion&quot; md-pos=&quot;8938-8961&quot;&gt;&lt;a href=&quot;#4-summery--conculsion&quot; name=&quot;4-summery--conculsion&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4. Summery / Conculsion&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;8963-8984&quot;&gt;&lt;code md-pos=&quot;8966-8980&quot;&gt;persistent.xml&lt;/code&gt;설정&lt;/li&gt;
  &lt;li md-pos=&quot;8984-9066&quot;&gt;앤티티 매니저 팩토리 -&amp;gt; 앤티티 매니저 -&amp;gt; 트랜잭션 획득 -&amp;gt; 비지니스 로직 수행 -&amp;gt; 앤티티 매니저 종료 -&amp;gt; 앤티티 매니저 팩토리 종료&lt;/li&gt;
  &lt;li md-pos=&quot;9066-9117&quot;&gt;매핑 애너테이션 : &lt;code md-pos=&quot;9080-9087&quot;&gt;@Entity&lt;/code&gt;, &lt;code md-pos=&quot;9091-9097&quot;&gt;@Table&lt;/code&gt;, &lt;code md-pos=&quot;9101-9108&quot;&gt;@Column&lt;/code&gt;, &lt;code md-pos=&quot;9112-9115&quot;&gt;@Id&lt;/code&gt;&lt;/li&gt;
  &lt;li md-pos=&quot;9117-9277&quot;&gt;앤티티 매니저 메서드
    &lt;ul&gt;
      &lt;li md-pos=&quot;9133-9152&quot;&gt;&lt;code md-pos=&quot;9136-9145&quot;&gt;persist()&lt;/code&gt; : 저장&lt;/li&gt;
      &lt;li md-pos=&quot;9154-9172&quot;&gt;&lt;code md-pos=&quot;9157-9165&quot;&gt;remove()&lt;/code&gt; : 삭제&lt;/li&gt;
      &lt;li md-pos=&quot;9174-9193&quot;&gt;&lt;code md-pos=&quot;9177-9183&quot;&gt;find()&lt;/code&gt; : 한건 조회&lt;/li&gt;
      &lt;li md-pos=&quot;9195-9277&quot;&gt;JPQL : 목록 조회
        &lt;ul&gt;
          &lt;li md-pos=&quot;9214-9243&quot;&gt;&lt;code md-pos=&quot;9217-9230&quot;&gt;createQuery()&lt;/code&gt; : 쿼리 객체 생성&lt;/li&gt;
          &lt;li md-pos=&quot;9247-9277&quot;&gt;&lt;code md-pos=&quot;9250-9265&quot;&gt;getResultList()&lt;/code&gt; : 결과 값 호출&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <category>JPA</category>
      <category>JPA</category>
      <category>ORM</category>
      <category>persistence.xml</category>
      <author>더블에스님</author>
      <guid isPermaLink="true">https://doublesprogramming.tistory.com/258</guid>
      <comments>https://doublesprogramming.tistory.com/258#entry258comment</comments>
      <pubDate>Wed, 13 Mar 2019 21:21:48 +0900</pubDate>
    </item>
    <item>
      <title>JPA 기본 개념</title>
      <link>https://doublesprogramming.tistory.com/257</link>
      <description>&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_layout-fx.css&quot;&gt;
&lt;style&gt;
.container { width: 100%; }
.wiki-container { width: 100%; }
.wiki-body { width: 100%; }
&lt;/style&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_default-fx.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism-default.css&quot;&gt;
&lt;title&gt;ch01-jpa-introduction.md&lt;/title&gt;
&lt;script src=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism.pack.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;blockquote&gt;
  &lt;p md-pos=&quot;2-161&quot;&gt;본 글은 &lt;a href=&quot;https://book.naver.com/bookdb/book_detail.nhn?bid=9252528&quot; md-pos=&quot;7-87&quot;&gt;자바 ORM 표준 JPA 프로그래밍&lt;/a&gt;를 읽고 개인적으로
  학습한 내용 복습하기 위해 작성된 글로 내용상 오류가 있을 수 있습니다. 오류가 있다면 지적 부탁 드리겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;jpa란&quot; md-pos=&quot;165-170&quot;&gt;&lt;a href=&quot;#jpa란&quot; name=&quot;jpa란&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;JPA란?&lt;/h1&gt;
&lt;h2 id=&quot;1-jpa-기본-개념&quot; md-pos=&quot;175-187&quot;&gt;&lt;a href=&quot;#1-jpa-기본-개념&quot; name=&quot;1-jpa-기본-개념&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1. JPA 기본 개념&lt;/h2&gt;
&lt;p md-pos=&quot;189-304&quot;&gt;&lt;strong md-pos=&quot;191-301&quot;&gt;JPA는 자바 진영의 ORM 기술 표준으로 애플리케이션과 JDBC 사이에서 작동한다.
여기서 ORM(Object-Relational Mapping)은 객체와 관계형 데이터베이스를
매핑한다는 뜻이다.&lt;/strong&gt;&lt;/p&gt;
&lt;pre md-pos=&quot;305-350&quot; class=&quot;line-numbers&quot;&gt;&lt;code md-pos=&quot;309-346&quot;&gt;자바 애플리케이션 --- JPA -- JDBC &amp;lt;-----&amp;gt; DB
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;351-568&quot;&gt;ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 해결해준다.
객체를 데이터베이스에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를
마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다. 그러면 ORM 프레임워크가
적절한 INSERT SQL을 생성해 데이터베이스에 객체를 저장해준다. 조회할 때도 JPA를 통해
객체를 직접 조회하면 된다.&lt;/p&gt;
&lt;p md-pos=&quot;569-748&quot;&gt;ORM 프레임워크는 단순히 SQL을 개발자 대신 생성해서 데이터베이스에 전달해주는 것뿐만
아니라 패러다임의 불일치 문제들도 해결해준다. 객체 측먄에서 정교한 모델링을 할 수 있고,
관계형 데이터베이스는 데이터베이스에 맞게 모델링을 하면된다. 이 둘을 어떻게 매핑해야하는지
매핑 방법만 ORM 프레임워크에 알려주면 된다.&lt;/p&gt;
&lt;p md-pos=&quot;749-817&quot;&gt;이렇게 되면 개발자는 데이터 중심인 관계형 데이터 베이스를 사용하더라도 객체지향 애플리케이션
개발에 집중을 할 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;2-jpa를-사용해야는-이유&quot; md-pos=&quot;821-838&quot;&gt;&lt;a href=&quot;#2-jpa를-사용해야는-이유&quot; name=&quot;2-jpa를-사용해야는-이유&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2. JPA를 사용해야는 이유?&lt;/h2&gt;
&lt;p md-pos=&quot;840-867&quot;&gt;그렇다면 JPA를 사용해야하는 이유를 알아보자.&lt;/p&gt;
&lt;h3 id=&quot;21-생산성&quot; md-pos=&quot;872-879&quot;&gt;&lt;a href=&quot;#21-생산성&quot; name=&quot;21-생산성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.1 생산성&lt;/h3&gt;
&lt;p md-pos=&quot;881-987&quot;&gt;JPA를 사용하면 자바 컬레션에 객체를 저장하듯 JPA에게 저장할 객체를 전달하면 된다. INSERT
SQL을 작성하고 JDBC API를 사용하는 반복적인 작업을 JPA가 대신 처리해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;988-1068&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;996-1064&quot;&gt;jpa.pesist(member); // 저장
Member member = jpa.find(memberId); // 조회
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;1069-1111&quot;&gt;반복적인 코드와 CRUD SQL을 개발자가 직접 작성하지 않아도 된다.&lt;/li&gt;
  &lt;li md-pos=&quot;1111-1138&quot;&gt;DDL문을 자동으로 생성해주는 기능도 있다.&lt;/li&gt;
  &lt;li md-pos=&quot;1138-1197&quot;&gt;위의 기능들을 사용함으로써 데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 역전시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;22-유지보수&quot; md-pos=&quot;1202-1210&quot;&gt;&lt;a href=&quot;#22-유지보수&quot; name=&quot;22-유지보수&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.2 유지보수&lt;/h3&gt;
&lt;p md-pos=&quot;1212-1386&quot;&gt;SQL에 의존적인 개발을 하거나 SQL을 직접 다루면 엔티티에 필드를 하나만 추가해도 관련된 등록, 수정, 조회
SQL과 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야한다. JPA를 사용하게 되면 이러한 과정을 JPA가
대신 처리해주기 때문에 필드를 추가, 삭제하더라도 수정해야할 코드가 줄어든다.&lt;/p&gt;
&lt;p md-pos=&quot;1387-1453&quot;&gt;즉 다시말해 객체지향 언어가 가진 장점을 활용하여 유연하고 유지보수하기 좋은 도메인 모델을 편리하게 설계할
수 있다.&lt;/p&gt;
&lt;h3 id=&quot;23-패러다임-불일치-해결&quot; md-pos=&quot;1458-1473&quot;&gt;&lt;a href=&quot;#23-패러다임-불일치-해결&quot; name=&quot;23-패러다임-불일치-해결&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.3 패러다임 불일치 해결&lt;/h3&gt;
&lt;p md-pos=&quot;1475-1529&quot;&gt;JPA는 상속, 연관관계, 객체 그래프 탐색, 비교와 같은 패러다임의 불일치 문제를 해결해준다.&lt;/p&gt;
&lt;h3 id=&quot;24-성능&quot; md-pos=&quot;1534-1540&quot;&gt;&lt;a href=&quot;#24-성능&quot; name=&quot;24-성능&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.4 성능&lt;/h3&gt;
&lt;p md-pos=&quot;1542-1589&quot;&gt;JPA는 애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회를 제공해준다.&lt;/p&gt;
&lt;pre md-pos=&quot;1590-1705&quot; class=&quot;line-numbers&quot;&gt;&lt;code class=&quot;language-java&quot; md-pos=&quot;1598-1701&quot;&gt;String memberId = &amp;quot;helloId&amp;quot;;
Member member1 = jpa.find(memberId);
Member member2 = jpa.find(memberId);
&lt;/code&gt;&lt;/pre&gt;
&lt;p md-pos=&quot;1706-1879&quot;&gt;위와 같이 같은 트랜잭션 안에서 같은 회원을 두번 조회할 경우, JDBC API를 사용해서 해당 코드를 직접 작성했다면
회원을 조회할 때마다 데이터베이스와 SELECT SQL을 통해 두번 통신을 했을 것이다. 하지만 JPA를 사용하면
SQL을 하번만 데이터베이스에 전달하고 두번째는 조회한 객체를 재사용한다.&lt;/p&gt;
&lt;h3 id=&quot;25-데이터-접근-추상화와-벤더-독립성&quot; md-pos=&quot;1884-1906&quot;&gt;&lt;a href=&quot;#25-데이터-접근-추상화와-벤더-독립성&quot; name=&quot;25-데이터-접근-추상화와-벤더-독립성&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2.5 데이터 접근 추상화와 벤더 독립성&lt;/h3&gt;
&lt;p md-pos=&quot;1908-2050&quot;&gt;관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다른 경우가 많다. 페이징 처리의 경우 데이터베이스마다
달라서 사용법을 각가 배워야만 한다. 결국 애플리케이션은 처음 선택한 데이터베이스 기술에 종속되고 다른 데이터베이스로
변경하기가 어려워지게 된다.&lt;/p&gt;
&lt;p md-pos=&quot;2051-2228&quot;&gt;JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공하여 특정 데이터베이스 기술에 종속되지
않도록 한다. 만약 데이터베이스를 변경하면 JPA에게 데이터베이스의 변경을 알려주기만 하면된다. JPA를 사용하면
로컬개발 환경에서는 H2를 사용하고 사용환경은 오라클이나 MySQL을 사용할 수 있다.&lt;/p&gt;
&lt;pre md-pos=&quot;2229-2302&quot; class=&quot;line-numbers&quot;&gt;&lt;code md-pos=&quot;2233-2298&quot;&gt;JPA --사용--&amp;gt; Dialect &amp;lt;---- MySQLDialect, OracleDialect, H2Dialect
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-summery--conclusion&quot; md-pos=&quot;2306-2329&quot;&gt;&lt;a href=&quot;#3-summery--conclusion&quot; name=&quot;3-summery--conclusion&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3. Summery / Conclusion&lt;/h2&gt;
&lt;p md-pos=&quot;2331-2603&quot;&gt;JPA를 사용함으로써 보다 더 객체지향적인 프로그래밍을 설계할 수 있고, 유지보수 및 코드의 변경에 유연하게
대처할 수 있다는 것을 알수 있었다. 하지만 JPA를 사용한다고 해서 SQL과 데이터베이스를 몰라도 되는 것이 아니라
오히려 좀더 깊게 공부를 해야한다는 것도 알았다. 저자의 말처럼 ORM이 객체지향과 관계형데이터베이스라는 두
기둥 위에 있기 때문이다. 그래서 데이터베이스와 객체를 올바르게 매핑하고 사용하기 위해서는 양쪽 모두를 이해하기
위해 좀더 공부를 더 많이 해야겠다.&lt;/p&gt;
&lt;/article&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <category>JPA</category>
      <category>JPA</category>
      <author>더블에스님</author>
      <guid isPermaLink="true">https://doublesprogramming.tistory.com/257</guid>
      <comments>https://doublesprogramming.tistory.com/257#entry257comment</comments>
      <pubDate>Wed, 13 Mar 2019 21:19:42 +0900</pubDate>
    </item>
    <item>
      <title>Git - 커밋 메시지 컨벤션</title>
      <link>https://doublesprogramming.tistory.com/256</link>
      <description>&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_layout-fx.css&quot;&gt;
&lt;style&gt;
.container { width: 100%; }
.wiki-container { width: 100%; }
.wiki-body { width: 100%; }
&lt;/style&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_default-fx.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism-default.css&quot;&gt;
&lt;title&gt;02_commit_message_rule.md&lt;/title&gt;
&lt;script src=&quot;file:///Users/doubles/.markdownNavigator/multimarkdown_prism.pack.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;h1 id=&quot;git---commit-message-convention&quot; md-pos=&quot;2-33&quot;&gt;&lt;a href=&quot;#git---commit-message-convention&quot; name=&quot;git---commit-message-convention&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;Git - Commit Message Convention&lt;/h1&gt;
&lt;p md-pos=&quot;35-110&quot;&gt;커밋 메시지를 작성할 때는 원칙을 정하고 일관성 있게 작성해야 한다. 아래는 유다시티의 커밋 메시지 스타일
가이드를 참조한 내용이다.&lt;/p&gt;
&lt;h2 id=&quot;1-commit-message-structure&quot; md-pos=&quot;114-141&quot;&gt;&lt;a href=&quot;#1-commit-message-structure&quot; name=&quot;1-commit-message-structure&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;1. Commit Message Structure&lt;/h2&gt;
&lt;p md-pos=&quot;143-181&quot;&gt;기본적으로 커밋 메시지는 아래와 같이 제목/본문/꼬리말로 구성한다.&lt;/p&gt;
&lt;pre md-pos=&quot;182-219&quot; class=&quot;line-numbers&quot;&gt;&lt;code md-pos=&quot;186-215&quot;&gt;type : subject

body

footer
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;2-commit-type&quot; md-pos=&quot;223-237&quot;&gt;&lt;a href=&quot;#2-commit-type&quot; name=&quot;2-commit-type&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;2. Commit Type&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;238-257&quot;&gt;feat : 새로운 기능 추가&lt;/li&gt;
  &lt;li md-pos=&quot;257-271&quot;&gt;fix : 버그 수정&lt;/li&gt;
  &lt;li md-pos=&quot;271-286&quot;&gt;docs : 문서 수정&lt;/li&gt;
  &lt;li md-pos=&quot;286-326&quot;&gt;style : 코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우&lt;/li&gt;
  &lt;li md-pos=&quot;326-347&quot;&gt;refactor : 코드 리펙토링&lt;/li&gt;
  &lt;li md-pos=&quot;347-379&quot;&gt;test : 테스트 코드, 리펙토링 테스트 코드 추가&lt;/li&gt;
  &lt;li md-pos=&quot;379-410&quot;&gt;chore : 빌드 업무 수정, 패키지 매니저 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;3-subject&quot; md-pos=&quot;414-424&quot;&gt;&lt;a href=&quot;#3-subject&quot; name=&quot;3-subject&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;3. Subject&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;426-469&quot;&gt;제목은 50자를 넘기지 않고, 대문자로 작성하고 마침표를 붙이지 않는다.&lt;/li&gt;
  &lt;li md-pos=&quot;469-540&quot;&gt;과거시제를 사용하지 않고 명령어로 작성한다.
    &lt;ul&gt;
      &lt;li md-pos=&quot;498-518&quot;&gt;&amp;quot;Fixed&amp;quot; --&amp;gt; &amp;quot;Fix&amp;quot;&lt;/li&gt;
      &lt;li md-pos=&quot;520-540&quot;&gt;&amp;quot;Added&amp;quot; --&amp;gt; &amp;quot;Add&amp;quot;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;4-body&quot; md-pos=&quot;544-551&quot;&gt;&lt;a href=&quot;#4-body&quot; name=&quot;4-body&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;4. Body&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;553-591&quot;&gt;선택사항이기 때문에 모든 커밋에 본문내용을 작성할 필요는 없다.&lt;/li&gt;
  &lt;li md-pos=&quot;591-627&quot;&gt;부연설명이 필요하거나 커밋의 이유를 설명할 경우 작성해준다.&lt;/li&gt;
  &lt;li md-pos=&quot;627-666&quot;&gt;72자를 넘기지 않고 제목과 구분되기 위해 한칸을 띄워 작성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;5-footer&quot; md-pos=&quot;670-679&quot;&gt;&lt;a href=&quot;#5-footer&quot; name=&quot;5-footer&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;5. footer&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;681-718&quot;&gt;선택사항이기 때문에 모든 커밋에 꼬리말을 작성할 필요는 없다.&lt;/li&gt;
  &lt;li md-pos=&quot;718-750&quot;&gt;issue tracker id를 작성할 때 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;6-example&quot; md-pos=&quot;754-764&quot;&gt;&lt;a href=&quot;#6-example&quot; name=&quot;6-example&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;6. Example&lt;/h2&gt;
&lt;pre md-pos=&quot;766-1804&quot; class=&quot;line-numbers&quot;&gt;&lt;code md-pos=&quot;770-1800&quot;&gt;feat: Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequenses of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;7-my-thought--conclusion--summery&quot; md-pos=&quot;1808-1844&quot;&gt;&lt;a href=&quot;#7-my-thought--conclusion--summery&quot; name=&quot;7-my-thought--conclusion--summery&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;7. My Thought / Conclusion / Summery&lt;/h2&gt;
&lt;p md-pos=&quot;1846-1974&quot;&gt;&lt;img src=&quot;https://github.com/walbatrossw/TIL/blob/master/01_cs-basic/git/img/before-commit-message.png?raw=true&quot; alt=&quot;before-commit-message&quot; md-pos=&quot;1846-1973&quot; /&gt;&lt;/p&gt;
&lt;p md-pos=&quot;1975-2234&quot;&gt;위와 같이 그동안 커밋을 하면서 메시지에는 몇번째 커밋인지 그리고 뭘 했는지에 대해서만 간략하게 작성했다.
나 나름의 규칙이라고 생각해서 그렇게 작성했던 것 같다. 하지만 커밋 메시지에도 나름의 규칙과 일관성을 가져야
한다는 것을 알면서도 제대로 실처하지 못했다. 그래서 개발을 하고나서 문제점이 발생하고 어떻게 해결했는지를
찾으려면 좀처첨 헷갈려서 찾을 수가 없었던 적이 많았다. 물론 문제점을 해결한 상황을 따로 정리하지 않은 것이
가장 큰 문제이기도 하다.&lt;/p&gt;
&lt;p md-pos=&quot;2235-2328&quot;&gt;앞으로는 위의 규칙을 지키면서 커밋 메시지를 작성하는 노력을 기울여 보자. 그렇게 하면 따로 시간을 내서
문제 상황을 해결한 내용들을 정리할 필요도 없어질 듯 하다.&lt;/p&gt;
&lt;h2 id=&quot;8-references&quot; md-pos=&quot;2332-2345&quot;&gt;&lt;a href=&quot;#8-references&quot; name=&quot;8-references&quot; class=&quot;anchor&quot;&gt;&lt;span class=&quot;octicon octicon-link&quot;&gt;&lt;/span&gt;&lt;/a&gt;8. References&lt;/h2&gt;
&lt;ul&gt;
  &lt;li md-pos=&quot;2347-2406&quot;&gt;&lt;a href=&quot;http://sujinlee.me/professional-github/&quot; md-pos=&quot;2349-2405&quot;&gt;깃허브로 취업하기 포스팅&lt;/a&gt;&lt;/li&gt;
  &lt;li md-pos=&quot;2406-2473&quot;&gt;&lt;a href=&quot;https://udacity.github.io/git-styleguide/&quot; md-pos=&quot;2408-2472&quot;&gt;유다시티 커밋 메시지 스타일 가이드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/article&gt;
&lt;/body&gt;
&lt;/html&gt;</description>
      <category>컴퓨터공학 기초/깃</category>
      <category>Git</category>
      <category>커밋 메시지 규칙</category>
      <category>커밋 메시지 컨벤션</category>
      <author>더블에스님</author>
      <guid isPermaLink="true">https://doublesprogramming.tistory.com/256</guid>
      <comments>https://doublesprogramming.tistory.com/256#entry256comment</comments>
      <pubDate>Sun, 10 Mar 2019 22:04:31 +0900</pubDate>
    </item>
  </channel>
</rss>