<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>y__hi_2X.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 29 Apr 2022 01:55:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>y__hi_2X.log</title>
            <url>https://images.velog.io/images/y__hi_24/profile/ff631365-2665-4572-a98f-1c799d8ed53c/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. y__hi_2X.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/y__hi_24" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Github] Intellij에서 Github 연결하기]]></title>
            <link>https://velog.io/@y__hi_24/GithubIntellij%EC%97%90%EC%84%9C-Github-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@y__hi_24/GithubIntellij%EC%97%90%EC%84%9C-Github-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 29 Apr 2022 01:55:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 Mac 환경 기준으로 작성된 글입니다.</p>
</blockquote>
<h3 id="1-intellij-idea--preferences-선택">1. IntelliJ IDEA &gt; Preferences 선택<img src="https://velog.velcdn.com/images/y__hi_24/post/93079810-f11c-4dc0-8a81-cd85304cc7ce/image.png" alt=""></h3>
<h3 id="2-version-control--github-선택-후-상단-메뉴의-log-in-to-github-enterprise-클릭">2. Version Control &gt; GitHub 선택 후 상단 메뉴의 &#39;Log In to GitHub Enterprise&#39; 클릭<img src="https://velog.velcdn.com/images/y__hi_24/post/e342375f-ff26-4ae9-99e8-eb7f83108aef/image.png" alt=""></h3>
<h3 id="3-generate-클릭">3. Generate 클릭<img src="https://velog.velcdn.com/images/y__hi_24/post/a1088ccf-a1b1-4824-9366-554e08e99821/image.png" alt=""></h3>
<h3 id="4-github-토큰-발급-화면의-토큰-복사-후-add-account-클릭">4. Github 토큰 발급 화면의 토큰 복사 후 &#39;Add Account&#39; 클릭<img src="https://velog.velcdn.com/images/y__hi_24/post/83327745-4cc9-404b-a014-b17930a29d0f/image.png" alt=""><img src="https://velog.velcdn.com/images/y__hi_24/post/1e192ba9-1f2f-46f4-860d-3cb401cec951/image.png" alt=""></h3>
<h3 id="5-정상-연결-시-아래와-같이-목록에-표시됨">5. 정상 연결 시 아래와 같이 목록에 표시됨<img src="https://velog.velcdn.com/images/y__hi_24/post/fd94be38-0145-4b95-aaf4-6bfb6d4f9263/image.png" alt=""></h3>
<hr>
<p>읽어주셔서 감사합니다 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Jasypt] 설정 파일 암호화]]></title>
            <link>https://velog.io/@y__hi_24/Jasypt-%EC%84%A4%EC%A0%95-%ED%8C%8C%EC%9D%BC-%EC%95%94%ED%98%B8%ED%99%94</link>
            <guid>https://velog.io/@y__hi_24/Jasypt-%EC%84%A4%EC%A0%95-%ED%8C%8C%EC%9D%BC-%EC%95%94%ED%98%B8%ED%99%94</guid>
            <pubDate>Thu, 03 Mar 2022 06:17:33 GMT</pubDate>
            <description><![CDATA[<p>일반적으로 프로젝트 초기 DB 설정 시 프로퍼티 파일이나 yml 파일에 DB 접속정보를 입력하게 됩니다.</p>
<p>이러한 정보가 포함된 소스를 Github와 같이 공개된 장소에 올리게 된다면 보안적으로 문제가 발생할 수 있습니다.</p>
<p>이번 글에서는 이러한 개발 정보를 암호화해주는 Jasypt 라이브러리에 대해 정리해보겠습니다~</p>
<hr>
<h2 id="💡jasypt란">💡Jasypt란?</h2>
<p>개발자가 간단히 프로젝트에 기본 암호화 기능을 사용할 수 있도록 지원해주는 Java 라이브러리입니다.</p>
<h2 id="jasypt-적용">Jasypt 적용</h2>
<p>실제로 Jasypt를 이용해 설정 파일 내 민감 정보를 암호화해보겠습니다.</p>
<h3 id="의존성-추가">의존성 추가</h3>
<p>먼저 암호화 기능을 사용하기 위해 dependencies에 해당 라이브러리를 추가해줍니다.</p>
<pre><code class="language-java">dependencies {
    implementation &#39;com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4&#39;
}</code></pre>
<h3 id="encrypt-key-생성">Encrypt Key 생성</h3>
<p><a href="https://www.devglan.com/online-tools/jasypt-online-encryption-decryption">Jasypt 암복호화 사이트</a>
jasypt 관련 설정 시 password를 설정하는 부분이 있는데 이 설정이 노출되는 경우 프로젝트 내에 암호화된 값을 복호화할 수 있기에, 위 사이트를 통해 jasypt password를 암호화합니다. </p>
<h3 id="config-생성">Config 생성</h3>
<pre><code class="language-java">@Configuration
@EnableEncryptableProperties
public class JasyptConfig {
    @Bean(name = &quot;encryptorBean&quot;)
    public StringEncryptor stringEncryptor(SimpleStringPBEConfig simpleStringPBEConfig) {
        PooledPBEStringEncryptor stringEncryptor = new PooledPBEStringEncryptor();
        stringEncryptor.setConfig(simpleStringPBEConfig);
        return stringEncryptor;
    }

    @Bean
    @ConfigurationProperties(&quot;config.encrypt&quot;)
    public SimpleStringPBEConfig simpleStringPBEConfig() {
        return new SimpleStringPBEConfig();
    }
}</code></pre>
<h3 id="설정-추가">설정 추가</h3>
<p><code>jasypt.ecryptor.bean</code>에 위 Config에서 명시한 Bean 입력
<code>config.ecrypt.password</code>는 위에서 사이트를 통해 암호화 한 password 입력</p>
<pre><code class="language-yml">jasypt:
  encryptor:
    bean: encryptorBean
config:
  encrypt:
    password: ie2Fa4lO1v1ODSx738OIUEiv/9rAFOqk
    algorithm: PBEWithMD5AndDES
    provider-name: SunJCE
    pool-size: 1
    key-obtention-iterations: 1000
    string-output-type: base64</code></pre>
<h3 id="테스트-함수를-이용해-암호화-password-구하기">테스트 함수를 이용해 암호화 password 구하기</h3>
<pre><code class="language-java">@SpringBootTest
class JasyptConfigTest {
    @Autowired
    @Qualifier(&quot;encryptorBean&quot;)
    private StringEncryptor stringEncryptor;

    @Test
    public void generatePassword() {
        String encrypt = stringEncryptor.encrypt(&quot;password&quot;);
        System.out.println(encrypt);
        String decrypt = stringEncryptor.decrypt(encrypt);
        System.out.println(decrypt);
    }
}</code></pre>
<h3 id="암호화-password-적용">암호화 password 적용</h3>
<p><code>ENC("암호화 password")</code> 형식으로 암호화된 값 적용</p>
<pre><code class="language-yml">spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306
    username: dbuser
    password: ENC(WHXxOvGjJa7qXjALhA7ghdoYksJjabL/)</code></pre>
<hr>
<p>🔗 참고 URL</p>
<ul>
<li><a href="http://www.jasypt.org/">http://www.jasypt.org/</a></li>
<li><a href="https://github.com/ulisesbocchio/jasypt-spring-boot">https://github.com/ulisesbocchio/jasypt-spring-boot</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] 자바 ORM 표준 프로그래밍 정리 #4]]></title>
            <link>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-4</link>
            <guid>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-4</guid>
            <pubDate>Fri, 18 Feb 2022 00:33:36 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 김영한님의 &#39;자바 ORM 표준 프로그래밍&#39; 교재를 바탕으로 정리한 글입니다. :)</p>
</blockquote>
<p>이번엔 JPA의 핵심 개념인 엔티티와 테이블 매핑에 대해 정리해보겠습니다~🤸</p>
<h2 id="매핑-어노테이션">매핑 어노테이션</h2>
<h3 id="entity">@Entity</h3>
<p>JPA를 사용해서 테이블과 매핑할 클래스에 사용한다.</p>
<p><strong>속성</strong></p>
<ul>
<li><strong>name</strong>: JPA에서 사용할 엔티티 이름 지정한다. 설정하지 않으면 클래스 이름을 그대로 사용.</li>
</ul>
<p><strong>주의사항</strong></p>
<ul>
<li>기본 생성자는 필수</li>
<li>final 클래스, inner 클래스, enum, interface에서 사용 불가</li>
<li>저장 필드에 final 사용 불가</li>
</ul>
<h3 id="table">@Table</h3>
<p>엔티티와 매핑할 테이블을 지정한다.</p>
<p><strong>속성</strong></p>
<ul>
<li><strong>name</strong>: 매핑할 테이블 이름(dafault: 엔티티 이름)</li>
<li><strong>catalog</strong>: 해당 기능이 있는 데이터베이스에서 매핑</li>
<li><strong>schema</strong>: 해당 기능이 있는 데이터베이스에서 매핑</li>
</ul>
<h2 id="스키마-자동-생성-설정">스키마 자동 생성 설정</h2>
<p>JPA는 클래스의 매핑 정보를 통해 각 데이터베이스에 맞게 스키마를 자동 생성하는 기능을 지원한다.</p>
<p>아래와 같은 설정을 통해 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성할 수 있다.</p>
<pre><code class="language-yml">spring:
  jpa:
    hibernate:
      ddl-auto: create</code></pre>
<p>위와 같이 설정 후 실행 시 콘솔에 출력되는 스키마 생성 로그. 기존 테이블을 삭제하고 재생성한다.</p>
<pre><code class="language-sql">drop table if exists member;

create table member (
    member_id bigint not null,
    city varchar(255),
    street varchar(255),
    zipcode varchar(255),
    username varchar(255),
    primary key (member_id)
)</code></pre>
<h3 id="hibernateddl-auto-속성">hibernate.ddl-auto 속성</h3>
<ul>
<li><strong>create</strong> : 기존 테이블을 삭제하고 새로 생성한다. DROP + CREATE</li>
<li><strong>create-drop</strong> : create 속성에 추가로 애플리케이션 종료 시 생성한 DDL을 제거한다. DROP + CREATE + DROP</li>
<li><strong>update</strong> : 테이블과 엔티티를 비교해 변경 사항을 수정한다.</li>
<li><strong>validate</strong> : 테이블과 엔티티를 비교해 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다.</li>
<li><strong>none</strong> : 자동 생성 기능 사용 X<blockquote>
<p>운영 환경에서 create, create-drop, update와 같이 DDL을 수정하는 옵션은 실사용되는 테이블이나 컬럼을 삭제할 수 있기 때문에 사용하면 안된다. </p>
</blockquote>
</li>
</ul>
<p>위 설정은 환경별로 알맞은 값을 사용해야 한다. 일반적으로 추천하는 상황별 전략은 아래와 같다.</p>
<ul>
<li>개발 초기: create, update</li>
<li>초기화 상태로 테스트를 진행하는 개발자 환경과 CI 서버: create, create-drop</li>
<li>테스트 서버: update, validate</li>
<li>스테이징, 운영: validate, none</li>
</ul>
<h3 id="제약조건-추가">제약조건 추가</h3>
<p>엔티티 관련 제약조건이 추가되는 경우 <strong>@Column의 속성</strong>을 이용해 이를 설정할 수 있다.</p>
<pre><code class="language-java">@Entity
public class Member {

    @Id
    @Column(name=&quot;member_id&quot;)
    private Long id;

    @Column(nullable = false, length = 20)
    private String username;
    ...
}</code></pre>
<p>위와 같이 자동 생성되는 DDL의 username 컬럼에 not null 제약조건과 length를 지정할 수 있으며 생성된 DDL은 아래와 같다.</p>
<pre><code class="language-sql">create table member (
       member_id bigint not null,
        city varchar(255),
        street varchar(255),
        zipcode varchar(255),
        username varchar(20) not null,
        primary key (member_id)
    )</code></pre>
<p><strong>@Table의 uniqueConstraints</strong> 속성을 통해 유니크 제약조건 부여도 가능한다.</p>
<pre><code class="language-java">@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(
                name = &quot;ID_NAME_UNIQUE&quot;,
                columnNames = {&quot;MEMBER_ID&quot;, &quot;USERNAME&quot;}
        )
})
public class Member {

    @Id
    @Column(name=&quot;member_id&quot;)
    private Long id;

    @Column(nullable = false, length = 20)
    private String username;
    ...
}</code></pre>
<p>생성된 DDL은 아래와 같다.</p>
<pre><code class="language-sql">alter table member 
       add constraint ID_NAME_UNIQUE unique (member_id, username)</code></pre>
<br>
위와 같은 기능들은 DDL을 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 끼치지 않는다. 그렇기에 스키마 자동 생성 기능을 사용하지 않는다면 위 설정을 할 필요는 없다.

<h2 id="기본키-매핑-전략">기본키 매핑 전략</h2>
<p>데이터베이스마다 기본 키를 생성하는 방식이 서로 달라 JPA는 이를 위해 기본 키 매핑 기능을 제공한다.</p>
<ul>
<li><strong>직접 할당</strong>: 기본 키를 애플리케이션에서 직접 할당, 식별자 값 없을 경우 예외 발생.<pre><code class="language-java">  @Entity
  public class Member {
      @Id
      private Long id;</code></pre>
</li>
<li><strong>IDENTITY</strong>: 기본 키 생성을 데이터베이스에 위임. 엔티티를 저장한 직후 할당된 식별자 값을 엔티티에서 조회해 저장.<pre><code class="language-java">  @Entity
  public class Member {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;</code></pre>
</li>
<li><strong>SEQUENCE</strong>: 데이터베이스 시퀀스를 통해 기본 키 할당. 엔티티 저장 시 시퀀스를 사용해 식별자를 먼저 조회한 후 이를 데이터베이스에 저장한다.<pre><code class="language-java">  @Entity
  public class Member {
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE,
                                generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
      private Long id;</code></pre>
</li>
<li><strong>TABLE</strong>: 키 생성용 테이블을 만들어 시퀀스처럼 사용. 내부 동작방식은 SEQUENCE 전략과 동일.<pre><code class="language-java">  @Entity
  public class Member {
      @Id
      @GeneratedValue(strategy = GenerationType.TABLE,
                                generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
      private Long id;</code></pre>
</li>
<li><strong>AUTO</strong>: 데이터베이스에 따라 알맞은 전략 선택(Default / Oracle: SEQUENCE, MySQL: IDENTITY)</li>
</ul>
<h2 id="필드와-컬럼-매핑">필드와 컬럼 매핑</h2>
<h3 id="enumerated">@Enumerated</h3>
<p>자바의 enum 타입을 매핑할 때 사용한다.</p>
<p>회원 별로 주소 정보를 가지고 있다고 가정할 때 주소 정보를 아래와 같이 JPA enum 어노테이션을 통해 표현할 수 있다.
<img src="https://images.velog.io/images/y__hi_24/post/77ac2982-e2be-41a2-9fa0-f5178ec59cd3/image.png" alt=""></p>
<pre><code class="language-java">@Entity
public class Member {
    @Id
    @GeneratedValue
    @Column(name=&quot;member_id&quot;)
    private Long id;

    private String username;

    @Embedded
    private Address address;
}

@Embeddable
public class Address {
    private String city;
    private String street;
    private String zipcode;
}</code></pre>
<hr>
<p>읽어주셔서 감사합니다~ :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] 자바 ORM 표준 프로그래밍 정리 #3]]></title>
            <link>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-3</link>
            <guid>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-3</guid>
            <pubDate>Thu, 10 Feb 2022 01:31:32 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 김영한님의 &#39;자바 ORM 표준 프로그래밍&#39; 교재를 바탕으로 정리한 글입니다. :)</p>
</blockquote>
<p>이번 글에서는 JPA의 강점 중 하나인 영속성 관리에 대해 설명해보겠습니다~!🕺💃</p>
<h2 id="엔티티-매니저">엔티티 매니저</h2>
<p><img src="https://images.velog.io/images/y__hi_24/post/8f067512-70cd-404f-ba26-13f0abfb4675/image.png" alt=""><strong>엔티티 매니저</strong>: 엔티티 저장, 수정, 조회 등 엔티티와 관련된 모든 일을 처리하며 데이터베이스 연결이 꼭 필요한 시점까지 커넥션을 얻지 않는다(ex: 트랜잭션 시작 시). 여러 스레드가 동시에 접근하면 동시성 문제가 발생하기에 스레드 간에 공유해선 안된다.</p>
<p><strong>엔티티 매니저 팩토리</strong>: 이름 그대로 엔티티 매니저를 만드는 공장으로, 이 공장을 만드는 비용이 상당히 크다. 때문에 애플리케이션 전체에서 엔티티 매니저 팩토리 하나를 공유해서 사용한다. 스프링 부트에서는 이를 자동으로 설정해준다.</p>
<h2 id="엔티티의-생명주기">엔티티의 생명주기</h2>
<p><img src="https://images.velog.io/images/y__hi_24/post/746b31bd-7dfc-49b2-b1ef-e03d5ab93e37/image.png" alt=""></p>
<ul>
<li>비영속(new/transient): 영속성 컨텍스트에 속하지 않은 상태</li>
<li>영속(managed): 영속성 컨텍스트에 저장된 상태</li>
<li>준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태</li>
<li>삭제(removed): 삭제된 상태</li>
</ul>
<h2 id="영속성-컨텍스트">영속성 컨텍스트</h2>
<p><strong>💡 영속성 컨텍스트란?</strong> 
JPA를 이해하는 데 있어 가장 중요한 개념이다. &#39;엔티티를 영구 저장하는 환경&#39;이라는 뜻으로 엔티티 매니저로 엔티티를 저장하거나 조회할 때 영속성 컨텍스트에 엔티티가 1차적으로 보관 및 관리된다.</p>
<h3 id="특징">특징</h3>
<ul>
<li><strong>식별자 값으로 구분</strong>
영속성 컨텍스트는 엔티티를 식별자 값(@Id, 테이블의 기본 키에 매핑)으로 구분하기에 식별자 값이 반드시 있어야 한다.</li>
<li><strong>트랜잭션 커밋 시 데이터베이스에 저장</strong>
JPA는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 저장된 엔티티를 데이터베이스를 반영한다. 이것을 플러시(flush)라 한다.</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li><p><strong>1차 캐시</strong>
영속성 컨텍스트는 내부에 캐시를 가지고 있는데 이것을 1차 캐시라 한다. 캐시에 저장된 엔티티는 @Id로 매핑된 식별자로 구분된다. 
엔티티 조회 시 가장 먼저 메모리에 있는 1차 캐시를 검색한다. 만약 찾는 엔티티가 캐시에 없으면 엔티티 매니저는 데이터베이스를 조회해 엔티티를 생성한 후 1차 캐시에 저장한 뒤 해당 엔티티를 반환한다.
아래 예시 코드로 관련 내용을 확인할 수 있다. </p>
<p><img src="https://images.velog.io/images/y__hi_24/post/0590809e-01b8-4ea4-b6e0-532643b9b749/image.png" alt="1차 캐시에서 조회"></p>
<p><img src="https://images.velog.io/images/y__hi_24/post/44e162cd-fcf7-442d-821c-38fec2bd5d33/image.png" alt="DB에서 조회"></p>
</li>
</ul>
<pre><code class="language-java">   Member member = new Member();
   member.setId(&quot;member1&quot;);

   //1차 캐시에 저장
   em.persit(member);

   //1차 캐시에서 조회
   Member findMember1 = em.find(Member.class, &quot;member1&quot;);

   //DB에서 조회
   Member findMember2 = em.find(Member.class, &quot;member2&quot;);</code></pre>
<ul>
<li><p><strong>동일성 보장</strong>
아래와 같이 동일 식별자로 같은 엔티티를 여러번 조회하는 경우, 영속성 컨텍스트가 1차 캐시에 있는 같은 인스턴스를 계속 반환해 성능상 이점과 엔티티의 동일성을 보장한다.</p>
<pre><code class="language-java"> Member a = em.find(Member.class, &quot;member1&quot;);
 Member b = em.find(Member.class, &quot;member1&quot;);

 System.out.println(a == b); //true</code></pre>
</li>
<li><p><strong>트랙잭션을 지원하는 쓰기 지연</strong>
엔티티 매니저는 트랜잭션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 SQL을 모아둔다. 그래고 트랜잭션 커밋 시 모아둔 쿼리를 동시에 보낸다. 이 기능을 통해 모아둔 등록 쿼리를 데이터베이스에 한 번에 전달하면 성능을 최적화할 수 있다.
<img src="https://images.velog.io/images/y__hi_24/post/44d8055f-fe09-4fc7-abee-61cf5a1ca8dd/image.png" alt=""></p>
</li>
<li><p><strong>변경 감지</strong>
JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태인 스냅샷을 복사해서 저장한다. 그리고 플러시 시점에 스냅샷과 엔티티를 비교해 변경이 감지되었을때 수정 쿼리를 생성해 내부 쿼리 저장소에 저장한다.
<img src="https://images.velog.io/images/y__hi_24/post/a5c979c5-ff20-4290-aac9-4e808115ba54/image.png" alt="">
또한 JPA 기본 전략으로 인해 변경 감지 시 모든 필드가 업데이트 된다. 이 전략은 수정 쿼리가 항상 같고 데이터베이스에서 한 번 파싱된 쿼리를 재사용할 수 있다는 장점이 있다.</p>
<blockquote>
<p>필드가 많거나 저장되는 내용이 너무 큰 경우에는 하이버네이트 확장 기능(@DynamicUpdate)를 사용하면 되지만, 이를 사용하면 캐시된 쿼리를 사용하지 않고 새로운 쿼리를 생성해 오버헤드가 발생한다고 합니다... 약 30개 정도되는 컬럼을 수정하는 경우는 되어야 기본 전략보다 빠르다고 하네요...</p>
</blockquote>
</li>
</ul>
<h2 id="플러시">플러시</h2>
<p>플러시(flush)는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다. 실행 시 변경 감지가 동작해 수정 엔티티에 대한 쿼리를 생성하고 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.</p>
<h3 id="호출-방법">호출 방법</h3>
<p>플러시 호출 방법은 아래 세 가지가 있다.</p>
<ul>
<li><strong>직접 호출</strong>: flush() 함수를 직접 호출해 영속성 컨텍스트를 강제로 플러시한다. 테스트나 특수한 경우를 제외하고 거의 사용하지 않는다.</li>
<li><strong>트랜잭션 커밋 시 자동 호출</strong>: JPA는 트랜잭션 커밋 시 플러시를 자동으로 호출해준다.</li>
<li><strong>JPQL 실행 시 자동 호출</strong>: JPQL과 같은 객체지향 쿼리를 호출할 때도 JPA가 자동으로 플러시를 호출해준다.</li>
</ul>
<h3 id="옵션">옵션</h3>
<ol>
<li>FlushModeType.AUTO(Default): 커밋이나 쿼리 실행 시 플러시</li>
<li>FlushModeType.COMMIT: 커밋할 때만 플러시<pre><code class="language-java">em.setFlushMode(FlushModeType.COMMIT);</code></pre>
</li>
</ol>
<h2 id="준영속">준영속</h2>
<p>준영속이란 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태로, 준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.</p>
<p>준영속 상태로 전환되는 경우는 아래 세가지이다.</p>
<ul>
<li><strong>준영속 상태로 전환: em.detach(entity)</strong>
영속성 컨텍스트에 더 이상 해당 엔티티를 관리하지 말라고 알려준다. 호출 시 1차 캐시와 쓰기 지연 SQL 저장소에서 해당 엔티티 관련된 모든 정보가 제거된다.</li>
<li><strong>영속성 컨텍스트 초기화: em.clear()</strong>
영속성 컨텍스트를 초기화해 모든 엔티티를 준영속 상태로 만든다.</li>
<li><strong>영속성 컨텍스트 종료: em.close()</strong>
영속성 컨텍스트 자체를 종료시킨다.</li>
</ul>
<h3 id="병합">병합</h3>
<p>준영속이나 비영속 상태의 엔티티를 영속 상태로 변경하기 위해 병합 함수인 merge()를 사용한다. 병합 함수는 파라미터로 엔티티를 받아 식별자로 영속성 컨텍스트와 데이터베이스를 조회한 후 찾는 엔티티가 없으면 받아온 엔티티 정보로 새로운 영속 상태의 엔티티를 생성해 반환한다.</p>
<pre><code class="language-java">public static void main(String args[]){
    Member member = createMember(&quot;memberA&quot;, &quot;userA&quot;);

    member = mergeMember(member);
}

public Member createMember(String id, String name){
    EntityManager em;

    //회원 생성
    Memeber member = new Member();
    member.setId(id);
    member.setName(name);

    em.persist(member);

    //영속성 컨텍스트 종료
    em.close();
}

public Member mergeMember(Member member){
    EntityManager em;

    //병합 엔티티 반환
    return em.merge(member);
}
</code></pre>
<hr>
<p>읽어주셔서 감사합니다. 🐥</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] 자바 ORM 표준 프로그래밍 정리 #2]]></title>
            <link>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-2</link>
            <guid>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-2</guid>
            <pubDate>Wed, 26 Jan 2022 04:13:42 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 김영한님의 &#39;자바 ORM 표준 프로그래밍&#39; 교재와 &#39;실전! 스프링 부트와 JPA 활용&#39; 강의를 바탕으로 정리한 글입니다. :)</p>
</blockquote>
<p>이번 글에서는 실제로 동작하는 JPA 소스에 대해 간단히 살펴보겠습니다. 😚</p>
<p>JPA 테스트 시 사용될 기본적인 프로젝트 세팅은 <a href="https://start.spring.io/">https://start.spring.io/</a> 페이지에서 진행할 수 있습니다.</p>
<h2 id="객체-매핑">객체 매핑</h2>
<p>JPA를 사용하려면 가장 먼저 클래스와 테이블을 매핑해야 한다. </p>
<h3 id="테이블">테이블</h3>
<p>예시로 아래와 같은 회원 테이블과 있다고 가정해보자.</p>
<pre><code class="language-sql">create table member
(
    member_id bigint       not null    primary key,
    name  varchar(255) null,
    city      varchar(255) null,
    street    varchar(255) null,
    zipcode   varchar(255) null
);</code></pre>
<h3 id="클래스">클래스</h3>
<p>회원 클래스에 JPA가 제공하는 매핑 어노테이션이 추가해 테이블을 표현할 수 있다.</p>
<pre><code class="language-java">@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name=&quot;member_id&quot;)
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = &quot;member&quot;)
    private List&lt;Order&gt; orderList = new ArrayList&lt;&gt;();
}</code></pre>
<ul>
<li><strong>@Entity</strong>
엔티티 클래스를 테이블과 매핑한다고 JPA에 알려준다.</li>
<li><strong>@Table</strong>
엔티티 클래스에 매핑할 테이블 정보를 알려준다. 여기서는 엔티티와 테이블 명이 동일하기에 생략되었다.</li>
<li><strong>@Id</strong>
필드를 테이블의 기본 키(Primary key)에 매핑한다.</li>
<li><strong>@GeneratedValue</strong>
기본키 매핑 전략
AUTO: 데이터베이스에 따라 알맞은 전략 선택(Default / Oracle: SEQUENCE, MySQL: IDENTITY)
IDENTITY: 기본 키 생성을 데이터베이스에 위임
SEQUENCE: 데이터베이스 시퀀스를 통해 기본 키 할당
TABLE: 키 생성용 테이블을 만들어 시퀀스처럼 사용</li>
<li><strong>@Column</strong>
필드를 컬럼에 매핑한다. 해당 어노테이션이 없는 경우 동일한 이름의 컬럼(대소문자 구분은 데이터베이스에 따라 다르므로 유의!)을 찾아 자동 매핑한다.</li>
<li><strong>@Embedded</strong>
사용자가 정의한 값 타입을 지정할 수 있다.(연관도 있는 값들로 분류해 응집력 ↑)</li>
<li><strong>@OneToMany</strong>
양방향 연관관계 매핑, 해당 어노테이션은 일대다 관계를 나타낸다.<h3 id="매핑-관계">매핑 관계</h3>
객체 매핑이 된 테이블과 클래스의 관계는 아래와 같이 나타난다.
<img src="https://images.velog.io/images/y__hi_24/post/742ec1a9-0aa4-4fae-8061-620e9f2bb06c/image.png" alt=""></li>
</ul>
<h2 id="비즈니스-로직">비즈니스 로직</h2>
<p>실제로 JPA를 이용하는 간단한 코드를 알아보도록 하자.</p>
<pre><code class="language-java">EntityManager em;

String memberId = &quot;user1&quot;;

Member member = new Member();
member.setId(memberId);
member.setName(&quot;James&quot;);
member.setId(20);

// 등록
em.persist(member);

// 조회
Member findMember = em.find(Member.class, memberId);

// 수정
member.setAge(21);

// 삭제
em.remove(member);
</code></pre>
<blockquote>
</blockquote>
<p><strong>수정의 경우</strong> 별도의 엔티티 매니저 함수를 이용하지 않고 단순히 엔티티의 값만 변경했다. JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖추고 있기에 <strong>엔티티의 값만 변경하면 자동으로 UPDATE문을 생성</strong>해 데이터베이스의 값을 변경한다.
엔티티 매니저는 엔티티의 등록, 조회, 삭제와 같은 기본적인 함수를 제공하기에 개발자는 SQL을 작성할 필요없이 이 함수를 이용하면 된다. 실제 SQL은 JPA가 자동으로 생성해 데이터베이스에 넘겨준다.</p>
<h2 id="jpql">JPQL</h2>
<p>위에서 예시로 든 예제는 엔티티 매니저의 함수를 통해 처리 가능한 단순한 코드였다. 하지만 실제 실무에서는 위 함수로 처리할 수 없는 복잡한 로직을 만들어야할 경우가 생긴다.
이에 JPA는 엔티티 객체를 대상으로 쿼리하는 JPQL을 제공한다.</p>
<pre><code class="language-java">EntityManager em;

List&lt;Member&gt; memberList = em.createQuery(&quot;select m from Member m&quot;, Member.class)
                .getResultList();</code></pre>
<p>JPQL은 위와 같이 엔티티 매니저의 createQuery 함수를 통해 쿼리 객체를 생성하며 이를 getResultList()로 리턴한다.</p>
<hr>
<p>읽어주셔서 감사합니다. 🙇‍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] 자바 ORM 표준 프로그래밍 정리 #1]]></title>
            <link>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-1</link>
            <guid>https://velog.io/@y__hi_24/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%A0%95%EB%A6%AC-1</guid>
            <pubDate>Wed, 19 Jan 2022 06:03:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 김영한님의 &#39;자바 ORM 표준 프로그래밍&#39; 교재를 바탕으로 정리한 글입니다. :)</p>
</blockquote>
<h2 id="💡jpa란">💡JPA란?</h2>
<p>객체와 관계형 DB 간의 차이를 해결해 주는 ORM 프레임워크이다. JPA는 개발자 대신 적절한 SQL(CRUD)를 생성해 데이터베이스에 전달해 줄 뿐만 아니라 기존 JDBC API의 패러다임 불일치 문제도 해결해 준다.
<img src="https://images.velog.io/images/y__hi_24/post/52c5de81-4390-489a-95a0-50797d6ddbce/JPA_architecture.png" alt=""></p>
<blockquote>
<p>ORM(Object-Relational Mapping)은 이름 그대로 객체와 관계형 데이터베이스를 매핑해준다. JPA는 이러한 ORM 기술에 대한 API 표준 명세이다. 
현재 다양한 ORM 프레임워크이 존재하지만 그중 하이버네이트가 가장 대중적으로 사용된다.</p>
</blockquote>
<h2 id="jpa의-필요성">JPA의 필요성</h2>
<h3 id="sql을-직접-다룰-때-발생하는-문제">SQL을 직접 다룰 때 발생하는 문제</h3>
<p><img src="https://images.velog.io/images/y__hi_24/post/e3197e4a-2a00-4f72-b497-0ca319192c68/JDBC_API.png" alt=""></p>
<ul>
<li><p><strong>객체와 데이터베이스 간 구조적 차이</strong>
보통 데이터베이스는 객체 구조와는 다른 데이터 중심의 구조를 가진다.
때문에 객체를 직접 DB에 저장하지 못하고 개발자가 객체와 DB 사이에서 SQL과 JDBC API를 이용해 변환 작업을 직접 해줘야 한다. 
이러한 이유로 애플리케이션이 점점 커질수록 작업해야 할 SQL과 API는 무수히 늘어날 것이다.</p>
</li>
<li><p><strong>SQL에 의존적인 개발</strong>
객체 간의 연관관계를 전적으로 SQL을 통해 표현하기 때문에 논리적으로 엔티티와 SQL 사이에 강력한 의존관계가 발생한다. 이로 인해 엔티티 수정이 필요할 경우 DAO를 열어 실행되는 SQL을 확인해야 하고 이는 진정한 의미의 계층 분할이 아니다.</p>
</li>
<li><p><strong>유지보수의 어려움</strong>
위와 같이 엔티티와 SQL 간 강력한 의존관계가 생긴다. 때문에 엔티티에 변경이 일어날 때 관련 DAO와 SQL 대부분을 변경해야 해 유지보수가 어려워지는 문제가 발생한다.</p>
</li>
</ul>
<h3 id="jpa의-장점">JPA의 장점</h3>
<ul>
<li><p><strong>생산성</strong>
기존에는 개발자가 SQL을 작성하고 JDBC API를 사용하는 반복적인 작업을 모두 진행해야 했지만 JPA는 이러한 작업을 모두 대신 처리해 준다.</p>
</li>
<li><p><strong>유지보수</strong>
SQL을 직접 다루는 경우, 엔티티에 변경이 일어나면 관련 SQL을 모두 수정하는 작업이 필요하다. 하지만 JPA를 사용하면 이러한 작업을 JPA가 대신해주기에 개발자가 유지보수해야할 코드 수가 적어진다.</p>
</li>
<li><p><strong>패러다임의 불일치 해결</strong>
상속, 연관관계, 객체 그래프 탐색, 비교하기와 같이 객체와 관계형 데이터베이스 사이에서 발생하는 패러다임 불일치 문제를 JPA를 사용해 해결할 수 있다.</p>
</li>
<li><p><strong>성능</strong>
JPA는 엔티티 매니저 내부에 영속성 컨텍스트를 두어 엔티티를 비휘발성으로 관리한다. 예를 들어 아래와 같이 같은 트랜잭션 안에서 동일 데이터를 조회하는 코드가 있다고 가정해 보자.</p>
<pre><code class="language-java">EntityManager em;

String memberId = &quot;user1&quot;;
Member member1 = em.find(memberID);
Member member2 = em.find(memberID);</code></pre>
<p>엔티티 매니저를 통해 데이터가 한 번 조회해왔다면 이 이후부터 조회되는 데이터는 엔티티 매니저에 이미 저장된 데이터를 조회하기 때문에 DB 통신을 여러 번 하지 않는다. 이러한 동작 방식을 통해 JPA는 애플리케이션과 데이터베이스 사이에서 최적화된 성능을 지원한다. </p>
</li>
<li><p><strong>데이터 접근 추상화와 벤더 독립성</strong>
아래와 같이 JPA는 애플리케이션과 데이터베이스 사이 추상화된 접근 계층을 제공하기에 특정 데이터베이스 기술에 종속되지 않는다. 때문에 데이터베이스를 변경하게 되더라도 일부 설정만 변경해 주면 된다.
<img src="https://images.velog.io/images/y__hi_24/post/fa7db281-9c89-4a24-99a2-5566d39b29b7/Dialect.png" alt=""></p>
</li>
<li><p><strong>표준</strong>
JPA는 자바 진영의 ORM 기술 표준이다.</p>
</li>
</ul>
<hr>
<p>읽어주셔서 감사합니다. 🥳</p>
]]></description>
        </item>
    </channel>
</rss>