<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>minmin_key.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 31 Aug 2021 07:26:13 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>minmin_key.log</title>
            <url>https://images.velog.io/images/minmin_key/profile/292444ff-acb9-436f-bd11-b54158121b9c/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. minmin_key.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/minmin_key" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[값 타입 - 불변 객체, 컬렉션]]></title>
            <link>https://velog.io/@minmin_key/%EA%B0%92-%ED%83%80%EC%9E%85-%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@minmin_key/%EA%B0%92-%ED%83%80%EC%9E%85-%EB%B6%88%EB%B3%80-%EA%B0%9D%EC%B2%B4-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Tue, 31 Aug 2021 07:26:13 GMT</pubDate>
            <description><![CDATA[<h3 id="값-타입과-불변-객체">값 타입과 불변 객체</h3>
<p>값 타입은 복잡한 객체 세상을 조금이라도 단순화하기 위한 개념이다. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.</p>
<h4 id="값-타입-공유-참조">값 타입 공유 참조</h4>
<ul>
<li>임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 부작용(side effect)가 발생할 수 있다
<img src="https://images.velog.io/images/minmin_key/post/9cd6dbde-ee27-4141-af88-9f44f660811b/image.png" alt="">위 그림과 같이 회원1은 OldCity를 멤버로 가지고 있지만 회원2도 city를 참조하게 되어 NewCity로 바꾸면 회원1의 멤버도 바뀌는 부작용이 발생한다.</li>
</ul>
<h4 id="값-타입-복사">값 타입 복사</h4>
<ul>
<li>값 타입의 실제 인스턴스 값을 공유하는 것은 위험하기 때문에 값(인스턴스)를 복사해서 사용해야 한다.
<img src="https://images.velog.io/images/minmin_key/post/c76e666c-6dd5-4f4b-a99b-ba484a0b312a/image.png" alt=""></li>
</ul>
<h4 id="객체-타입의-한계">객체 타입의 한계</h4>
<ul>
<li>항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다.</li>
<li>문제는 임베디드 타입처럼 <strong>직접 정의한 값 타입은 자바의 기본 타입이 아니라 객체 타입</strong>이다.</li>
<li>자바 기본 타입에 값을 대입하면 값을 복사히지만 <strong>객체 타입은 참조 값을 직접 대입하고 이것을 막을 방법이 없다.</strong></li>
<li><strong>객체의 공유 참조는 피할 수 없다.</strong>
<img src="https://images.velog.io/images/minmin_key/post/6395d511-a28f-426c-a193-64203b84074f/image.png" alt=""></li>
</ul>
<h4 id="불변-객체">불변 객체</h4>
<ul>
<li>객체 타입을 <strong>수정할 수 없게 만들면 부작용을 원천 차단</strong>할 수 있다.</li>
<li><strong>값 타입은 불변 객체(immutable object)로 설계해야 한다.</strong></li>
<li><strong>불변객체 : 생성 시점 이후 절대 값을 변경할 수 없는 객체</strong></li>
<li>생성자로만 값을 설정하고 수정자(Setter)를 만들지 않으면 된다.</li>
</ul>
<blockquote>
<p>Integer, String은 자바에서 제공하는 대표적인 불변 객체이다.</p>
</blockquote>
<h3 id="값-타입의-비교">값 타입의 비교</h3>
<h4 id="값-타입의-비교-1">값 타입의 비교</h4>
<ul>
<li><p>값 타입 : 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 한다.</p>
<pre><code class="language-java">int a = 10;
int b = 10;
// a == b -&gt; true

Address a = new Address(&quot;서울시&quot;);
Address b = new Address(&quot;서울시&quot;);
// a == b -&gt; false;</code></pre>
</li>
<li><p>동일성(identity) 비교 : 인스턴스의 참조 값을 비교, ==사용</p>
</li>
<li><p>동등성(equivalence) 비교 : 인스턴스의 값을 비교, equals()사용</p>
</li>
<li><p>값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야한다. 이때 값 타입의 equals() 메소드를 적절하게 재정의해야 한다. (주로 모든 필드 사용)</p>
</li>
</ul>
<h3 id="값-타입-컬렉션">값 타입 컬렉션</h3>
<p>값 타입을 컬렉션(Set, List 등)으로 가지는 것을 말한다. 이때 엔티티 내에서는 문제가 없지만 DB로 구현할 때 문제가 생긴다. 관계형 데이터베이스는 컬렉션을 테이블 안에 담을 수 있는 구조가 없다.
<img src="https://images.velog.io/images/minmin_key/post/031f103b-70d2-45a2-bcc8-cadecad76558/image.png" alt="">따라서 위 그림과 같이 컬렉션을 별도의 테이블로 나누어 관리하여 일대다 관계로 테이블을 구성해야 한다.</p>
<h4 id="값-타입-컬렉션-1">값 타입 컬렉션</h4>
<ul>
<li>값 타입을 하나 이상 저장할 때 사용</li>
<li>데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없기 때문에 컬렉션을 저장하기 위한 별도의 테이블이 필요하다.</li>
<li>@ElementCollection, @CollectionTable 사용
<img src="https://images.velog.io/images/minmin_key/post/9c430eb3-9059-4026-b9e6-978f30e77a69/image.png" alt=""></li>
</ul>
<h4 id="값-타입-컬렉션의-제약사항">값 타입 컬렉션의 제약사항</h4>
<ul>
<li>값 타입은 엔티티와 다르게 식별자 개념이 없다. 따라서 값을 변경하면 추적이 어렵다.</li>
<li>값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현제 값을 모두 다시 저장한다.</li>
<li>값 타입 컬렉션을 매핑하는 테이블은 모든 컬럽을 묶어서 기본키를 구성해야한다. -&gt; null 입력 불가, 중복 저장 불가</li>
</ul>
<h4 id="값-타입-컬렉션의-대안">값 타입 컬렉션의 대안</h4>
<ul>
<li>실무에서는 상황에 따라 <strong>값 타입 컬렉션 대신에 일대다 관계를 고려</strong>해야 하낟.</li>
<li>일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용한다.</li>
<li>영속성 전이(Cascade) + 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용하자.</li>
</ul>
<h3 id="정리">정리</h3>
<h4 id="엔티티-타입의-특징">엔티티 타입의 특징</h4>
<ul>
<li>식별자 존재</li>
<li>생명 주기 관리</li>
<li>공유<h4 id="값-타입의-특징">값 타입의 특징</h4>
</li>
<li>식별자 없음</li>
<li>생명 주기를 엔티티에 의존</li>
<li>공유하지 않는 것이 안전 (복사해서 사용)</li>
<li>불변 객체로 만드는 것이 안전<h4 id="값-타입은-정말-값-타입이라-판단될-때만-사용하자">값 타입은 정말 값 타입이라 판단될 때만 사용하자!</h4>
<h4 id="엔티티와-값-타입을-혼동해서-엔티티를-값-타입으로-만들면-안된다">엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들면 안된다!</h4>
<h4 id="식별자가-필요하고-지속해서-값을-추적-변경해야-한다면-값-타입이-아닌-엔티티를-사용하자">식별자가 필요하고, 지속해서 값을 추적, 변경해야 한다면 값 타입이 아닌 엔티티를 사용하자!!</h4>
</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[값 타입 - 기본값, 임베디드 타입]]></title>
            <link>https://velog.io/@minmin_key/%EA%B0%92-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8%EA%B0%92-%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@minmin_key/%EA%B0%92-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8%EA%B0%92-%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%ED%83%80%EC%9E%85</guid>
            <pubDate>Mon, 30 Aug 2021 07:20:51 GMT</pubDate>
            <description><![CDATA[<h3 id="jpa의-데이터-타입-분류">JPA의 데이터 타입 분류</h3>
<h4 id="엔티티-타입">엔티티 타입</h4>
<ul>
<li>@Entity로 정의하는 객체</li>
<li>데이터가 변해도 식별자로 지속해서 추적 가능하다.
(Ex. 회원 엔티티의 키나 나이 값을 변경해도 식별자로 인식 가능)</li>
</ul>
<h4 id="값-타입">값 타입</h4>
<ul>
<li>int, Integer, String과 같이 단순히 값으로 사용하는 자바 기본 타입이나 객체를 말한다.</li>
<li>식별자가 없고 값만 있으므로 변경시 추적이 불가능하다.
(Ex. 숫자 100을 200으로 변경하면 완전히 다른 값이 된다.)</li>
</ul>
<h4 id="값-타입-분류">값 타입 분류</h4>
<ul>
<li><strong>기본값 타입</strong><ul>
<li>자바 기본 타입(int, double)</li>
<li>래퍼 클래스(Integer, Long)</li>
<li>String</li>
<li><strong>임베디드 타입</strong>(Embedded Type, 복합 값 타입)</li>
</ul>
</li>
<li><strong>컬렉션 값 타입</strong>(Collection Value Type)</li>
</ul>
<h3 id="기본값-타입">기본값 타입</h3>
<ul>
<li>Ex. String name, int age 등</li>
<li><strong>생명주기를 엔티티에 의존</strong>한다.
(Ex. 회원을 삭제하면 이름, 나이 등 필드들도 함께 삭제된다.)</li>
<li>값 타입을 공유하면 안 된다!
(Ex. 회원 이름 변경 시 다른 회원의 이름도 함께 변경되면 안된다.)<blockquote>
<h4 id="참고-자바의-기본-타입은-절대-공유되지-않는다">참고. 자바의 기본 타입은 절대 공유되지 않는다.</h4>
<p>int, double과 같은 기본 타입(primitive type)은 항상 값을 복사하기 때문에 절대 공유되지 않는다.
하지만 Integer 같은 래퍼 클래스나 String 같은 특수한 클래스는 공유 가능한 객체이지만 변경되지 않는다.</p>
</blockquote>
</li>
</ul>
<h3 id="임베디드-타입-복합-값-타입">임베디드 타입 (복합 값 타입)</h3>
<h4 id="임베디드-타입">임베디드 타입</h4>
<ul>
<li>새로운 값 타입을 직접 정의할 수 잇다.</li>
<li>JPA는 임베디드 타입(embedded type)이라 한다.</li>
<li>주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 한다.</li>
<li>int, String과 같은 <strong>값 타입</strong>이기 때문에 <strong>변경하면 추적할 수 없다.</strong></li>
</ul>
<h4 id="임베디드-타입-예시">임베디드 타입 예시</h4>
<ul>
<li><p>회원 엔티티는 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편 번호를 가진다.
<img src="https://images.velog.io/images/minmin_key/post/db6d81d1-a35f-4a6c-8027-8e1ff657ba74/image.png" alt=""></p>
</li>
<li><p>회원 엔티티의 근무 시작일, 근무 종료일은 근무 기간으로, 주소들은 집 주소로 묶을 수 있을 것이다.
<img src="https://images.velog.io/images/minmin_key/post/5160b160-73d5-4eaa-b6ff-2756d1e34fac/image.png" alt=""></p>
</li>
<li><p>따라서 Period와 Address라는 클래스를 만들어 연결해주면 재사용성과 편의가 향상될 것이다.
<img src="https://images.velog.io/images/minmin_key/post/52cb9232-42bf-4635-8148-0eb9603a011a/image.png" alt=""></p>
</li>
<li><p>사용법</p>
<ul>
<li><p>@Embeddable : 값 타입을 정의 하는 곳에 표시
(값 타입 정의 시 기본 생성자는 필수이다.)</p>
</li>
<li><p>@Embedded : 값 타입을 사용하는 곳에 표시</p>
<pre><code class="language-java">    //값 타입 사용
    @Entity
    public class Member {
      ...
      @Embedded
      private Period workPeriod;
    }    

    ~~~~~~~~~~~~~~~~~~~~~~~~

    //값 타입 정의
    @Embeddable
    public class Period {
      private Date startDate;
      private Date endDate;
      //기본 생성자 필수
      public Period(...) { ... }
      //내부 메서드 사용 가능
      public boolean isWork() { ... }
    }</code></pre>
</li>
</ul>
</li>
</ul>
<h4 id="임베디드-타입의-장점">임베디드 타입의 장점</h4>
<ul>
<li>재사용성</li>
<li>높은 응집도</li>
<li>Period.isWork()과 같이 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다. 이를 통해 더욱 객체 지향적으로 프로그래밍이 가능하다.</li>
<li>임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티의 생명주기에 의존한다.</li>
</ul>
<h4 id="임베디드-타입과-테이블-매핑">임베디드 타입과 테이블 매핑</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/5c11b5a6-9b79-47a1-9b6b-12fa8adfb493/image.png" alt=""></p>
<ul>
<li>임베디드 타입은 엔티티의 값일 뿐이다.</li>
<li>임베디드 타입을 사용하기 전과 후에 <strong>매핑하는 테이블은 같다.</strong></li>
<li>객체와 테이블을 아주 세밀하게(find-grained) 매핑하는 것이 가능하다.</li>
<li>잘 설계한 ORM 어플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.</li>
</ul>
<h4 id="attributeoverride--속성-재정의">@AttributeOverride : 속성 재정의</h4>
<ul>
<li>한 엔티티 내에서 같은 값 타입을 사용하면 Column 명이 중복될 것이다. 이때 @AttributeOverride를 통해 Column 명 속성을 재정의하여 해결할 수 있다.</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[프록시와 연관관계 관리]]></title>
            <link>https://velog.io/@minmin_key/%ED%94%84%EB%A1%9D%EC%8B%9C%EC%99%80-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@minmin_key/%ED%94%84%EB%A1%9D%EC%8B%9C%EC%99%80-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Thu, 26 Aug 2021 08:17:53 GMT</pubDate>
            <description><![CDATA[<h3 id="프록시">프록시</h3>
<h4 id="프록시-1">프록시</h4>
<ul>
<li>프록시 조회 : <code>em.getReference()</code> 를 통해 데이터 베이스 조회를 미루는 가짜(프록시) Entity 객체를 조회한다.
(데이터 베이스를 통한 실제 Entity 객체 조회는 <code>em.find()</code>)<h4 id="프록시-객체">프록시 객체</h4>
</li>
<li>실제 클래스를 상속 받아서 만들어진다. 따라서 실제 클래스와 겉 모양이 같다.</li>
<li>프록시 객체는 실제 객체의 <strong>참조(target)</strong> 을 보관한다. 따라서 프록시 객체를 호출하면 참조(target)에 있는 실제 객체의 메소드를 대신 호출해 준다.
<img src="https://images.velog.io/images/minmin_key/post/c6cd9316-a398-4160-8a70-b20118893acd/image.png" alt=""></li>
</ul>
<h4 id="프록시-객체의-초기화">프록시 객체의 초기화</h4>
<ul>
<li>초기화 과정<pre><code class="language-java">//프록시 객체 조회
Member member = em.getReference(Member.class, &quot;id1&quot;);
member.getName();</code></pre>
위 코드가 실행되면 다음과 같은 과정이 진행된다.</li>
</ul>
<ol>
<li>Client가 프록시 객체의 메소드를 요청한다.</li>
<li>아직 프록시 객체는 초기화 되지 않아 프록시 객체 내의 target이 없기 때문에 JPA가 <strong>영속성 컨텍스트</strong>에 실제 객체를 가져오도록 <strong>초기화를 요청</strong>한다.</li>
<li>영속성 컨텍스트는 DB를 조회해서 원하는 실제 객체를 조회한다.</li>
<li>실제 객체를 생성한다.</li>
<li>target이 실제 객체와 연결되어 <code>target.getName()</code>을 실행할 수 있게 된다.
<img src="https://images.velog.io/images/minmin_key/post/1e9130ed-697c-4b9b-a3eb-583bf2afb1db/image.png" alt=""></li>
</ol>
<h4 id="프록시의-특징">프록시의 특징</h4>
<ul>
<li>프록시 객체는 처음 사용할 때 한 번만 초기화된다.</li>
<li>프록시 객체를 초기화 할 때, 프록시 객체가 실제 Entity로 바뀌는 것이 아니라 프록시 객체를 통해 실제 Entity에 접근 가능하다.</li>
<li>프록시 객체는 원본 Entity를 상속받기 때문에 타입 체크시 주의해야한다.
(== 비교는 실패하기 때문에 <code>instanceof</code>를 사용하자)</li>
<li>영속성 컨텍스트에 찾는 Entity가 이미 있으면 <code>em.getReference()</code>를 호출해도 실제 Entity를 반환한다. 
(이미 영속성 컨텍스트에 있기 때문에 프록시로 반환해봐야 이점이 없고, JPA는 같은 영속성 컨텍스트에서 가져오고 PK가 같으면 항상 같은 것을 반환해주는 것을 보장해주기 때문이다. 이러한 원칙 때문에 <code>em.getReference()</code>를 먼저 호출하고 <code>em.find()</code>를 호출하면 <code>em.find()</code>에도 프록시 객체를 반환한다.)</li>
<li>영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제가 발생한다.
(org.hibernate.LazyInitializationException 예외를 터트림)</li>
</ul>
<h4 id="프록시-확인">프록시 확인</h4>
<ul>
<li>프록시 인스턴스의 초기화 여부 확인
PersistenceUnitUtil.isLoaded(Object entity)</li>
<li>프록시 클래스 확인 방법
entity.getClass().getName() 출력</li>
<li>프록시 강제 초기화
org.hibernate.Hibernate.initialize(entity);</li>
</ul>
<h3 id="즉시-로딩과-지연-로딩">즉시 로딩과 지연 로딩</h3>
<h4 id="member를-조회할-때-team도-함께-조회해야-할까">Member를 조회할 때 Team도 함께 조회해야 할까?</h4>
<p>단순히 member 정보만 사용하는 비지니스 로직일 경우 member를 조회 할 때 team도 같이 조회하게 된다면 불필요한 cost가 발생한다. 이때 team을 프록시로 조회하게 된다면 DB에 접근하는 cost를 줄일 수 있을 것이다.
<img src="https://images.velog.io/images/minmin_key/post/b3c7cd81-f342-48bf-b17e-176398d07569/image.png" alt=""></p>
<h4 id="지연-로딩-lazy를-사용해서-프록시로-조회">지연 로딩 LAZY를 사용해서 프록시로 조회</h4>
<pre><code class="language-java">@Entity
public class Member {
  ...
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = &quot;TEAM_ID&quot;)
  private Team team;
  ...
}</code></pre>
<ul>
<li>내부 메커니즘
<img src="https://images.velog.io/images/minmin_key/post/dffd16a0-730a-46a2-9910-1f0897f02034/image.png" alt="">
<code>Member member = em.find(Member.class, 1L);</code> Member를 부를 때 Team은 프록시 객체로 생성된다.
<img src="https://images.velog.io/images/minmin_key/post/76e88ab1-da56-43ed-b0be-478cbda9178b/image.png" alt="">
<code>team.getName();</code> 이 코드와 같이 <strong>실제 team을 사용하는 시점</strong>에 DB를 조회하여 프록시 객체가 초기화 된다.</li>
</ul>
<h4 id="즉시-로딩-eager를-사용해서-함께-조회">즉시 로딩 EAGER를 사용해서 함께 조회</h4>
<p>만약 Member와 Team이 모두 필요한 경우 지연 로딩을 사용하면 네트워크를 2번 따로 접근하기 때문에 오히려 cost가 증가한다. 이럴 경우는 EAGER를 사용해서 Member와 Team을 함께 실제 객체로 조회하는 것이 이득일 것이다.</p>
<pre><code class="language-java">@Entity
public class Member {
  ...
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = &quot;TEAM_ID&quot;)
  private Team team;
  ...
}</code></pre>
<ul>
<li>내부 메커니즘
<img src="https://images.velog.io/images/minmin_key/post/788fc4a5-8e44-41c6-9eee-6d202a7e7f4c/image.png" alt="">
Member를 로딩할 때 조인하여 Team까지 같이 조회한다. JPA 구현체는 가능하면 조인을 사용해서 SQL 한번에 함께 조회한다.</li>
</ul>
<h4 id="프록시와-즉시-로딩-주의점">프록시와 즉시 로딩 주의점</h4>
<ul>
<li><strong>가급적 지연 로딩만 사용하자 (특히 실무에서)</strong></li>
<li>즉시 로딩을 적용하면 예상하지 못한 SQL이 발생한다.</li>
<li><strong>즉시 로딩은 JPQL에서 N+1 문제를 일으킨다.</strong>
  아래 코드가 실행 되면 JPQL은 SQL로 번역되어 실행된다. 아래  SQL이 그대로 실행되면서 Member만 조회하게 되고, Member를 조회하면서 EAGER이기 때문에 Team을 조회하는 SQL이 추가적으로 실행된다.
  이때 다른 Team일 경우 영속성 컨텍스트에 없기 때문에 추가적으로 조회하게 된다. 따라서 1개의 select문이 10개의 Member를 조회하게 되면 Team을 조회하는 SQL이 10번 실행되게 된다.
이처럼 1개의 select문이 N개의 select문을 추가로 부르기 때문에 N+1 문제라고 한다.<pre><code class="language-java">List&lt;Member&gt; members = em.createQuery(&quot;select m from Member m&quot;, Member.class)
  .getResultList();</code></pre>
이 문제를 해결하기 위해서는 LAZY로 변경한 후 fetch join을 사용해서 해결할 수 있다.<pre><code class="language-java">List&lt;Member&gt; members = em.createQuery(&quot;select m from Member m join fetch m.team&quot;, Member.class)
  .getResultList();</code></pre>
</li>
<li><strong>@ManyToOne, @OneToOne 즉시 로딩이 Default</strong>이다. 따라서 LAZY로 변경해 줘야 한다.</li>
<li>@OneToMany, @ManyToMany는 지연 로딩이 Default이다.</li>
</ul>
<h4 id="지연-로딩-활용---실무">지연 로딩 활용 - 실무</h4>
<ul>
<li><strong>모든 연관관계에 지연 로딩을 사용하자!!</strong></li>
<li><strong>실무에서 즉시 로딩을 사용하지 말자!!</strong></li>
<li>JPQL fetch 조인이나, Entity 그래프 기능을 사용하자!!</li>
<li>즉시 로딩은 상상하지 못한 쿼리가 나가게 된다.</li>
</ul>
<h3 id="영속성-전이--cascade">영속성 전이 : CASCADE</h3>
<h4 id="cascade">CASCADE</h4>
<ul>
<li>연관 관계나 즉시 로딩, 지연 로딩과 전혀 상관이 없다.</li>
<li>특정 Entity를 영속 상태로 만들 때 연관된 Entity도 함께 영속 상태로 만들고 싶을 때 사용한다.
(Ex. parent Entity를 저장할 때 child Entity도 저장하고 싶을 때)
<img src="https://images.velog.io/images/minmin_key/post/565349d8-a938-451e-ba69-e69e5bf936f8/image.png" alt=""></li>
</ul>
<h4 id="주의점">주의점</h4>
<ul>
<li>영속성 전이는 연관관계 매핑이나, 즉시 로딩, 지연 로딩과 전혀 관련이 없다.</li>
<li>단지 Entity를 영속화할 때 연관된 Entity도 함께 영속화하는 편리함을 제공할 뿐이다.</li>
<li>하위 Entity가 하나의 상위 Entity(단일 소유자)에만 연관되어 있다면 사용할 수 있다. 하지만 여러 상위 Entity와 연관되어 있다면 CASCADE사용하면 운영이 매우 힘들어지므로 사용하지 않는 것이 좋다.</li>
</ul>
<h4 id="cascade의-종류">CASCADE의 종류</h4>
<ul>
<li><strong>ALL : 모두 적용</strong></li>
<li><strong>PERSIST : 영속만</strong></li>
<li>REMOVE : 삭제만</li>
<li>MERGE, REFRESH, DETACH</li>
</ul>
<h3 id="고아-객체">고아 객체</h3>
<h4 id="고아-객체-1">고아 객체</h4>
<ul>
<li>고아 객체 제거 : 부모 Entity와 연관 관계가 끊어진 자식 Entity를 자동으로 삭제하는 기능이다.</li>
<li><strong>orphanRemoval = true</strong>
<img src="https://images.velog.io/images/minmin_key/post/b11e7131-f5db-4436-91dc-47071b33657a/image.png" alt=""></li>
<li>자식 Entity를 컬렉션에서 제거하면 자동으로 DB에 DELETE 쿼리가 나가서 DB에서도 삭제된다.<pre><code class="language-java">Parent parent1 = em.find(Parent.class, id);
parent1.getChildren().remove(0);
//자식 Entity를 제거 -&gt; DELETE 쿼리 전송</code></pre>
</li>
</ul>
<h4 id="주의점-1">주의점</h4>
<ul>
<li>참조가 제거된 Entity는 다른 곳에서 참조하지 안흔ㄴ 고아 객체로 보고 삭제하는 기능이다.</li>
<li><strong>참조하는 곳이 하나</strong>일 때 사용해야 한다. 즉 특정 Entity가 <strong>단일 소유</strong>할 때 사용해야 한다.</li>
<li>@OneToOne, @OneToMany만 사용 가능하다.</li>
<li>부모를 제거하면 자식은 고아가 된다. 따라서 고아 객체 제거 기능을 활성화하면, 부모를 제거할 때 자식도 함께 제거된다. 이것은 CascadeType.REMOVE처럼 동작한다.</li>
</ul>
<h3 id="영속성-전이--고아-객체-생명-주기">영속성 전이 + 고아 객체, 생명 주기</h3>
<ul>
<li><strong>CascadeType.ALL + orphanRemovel=true</strong></li>
<li>스스로 생명주기를 관리하는 Entity는 em.persist()로 영속화, em.remove()로 제거한다.</li>
<li>두 옵션을 모두 활성화하면 부모 Entity를 통해서 자식의 생명 주기를 관리할 수 있다.</li>
<li>도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용한다.</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[@MappedSuperclass]]></title>
            <link>https://velog.io/@minmin_key/MappedSuperclass</link>
            <guid>https://velog.io/@minmin_key/MappedSuperclass</guid>
            <pubDate>Thu, 26 Aug 2021 05:54:25 GMT</pubDate>
            <description><![CDATA[<h3 id="mappedsuperclass">@MappedSuperclass</h3>
<ul>
<li>공통 매핑 정보가 필요할 때 사용한다. 이때 DB 상에서는 서로 연관이 없으나 공통되는 속성이 존재할 때 편의를 위해 사용한다.
<img src="https://images.velog.io/images/minmin_key/post/f87a40b3-01ba-4b13-85d1-bca1d0df89de/image.png" alt=""></li>
<li>상속 관계 매핑이 아니다.</li>
<li>엔티디가 아니고, 테이블과 매핑하지 않는다.</li>
<li>부모 클래스를 상속 받는 <strong>자식 클래스에 매핑 정보만 제공</strong>한다.
(@Entity 클래스는 Entity나 @MappedSuperclass로 지정한 클래스만 상속 가능하다.)</li>
<li>조회, 검색 불가하다. <strong>(em.find(BaseEntity) 불가)</strong></li>
<li>직접 생성해서 사용할 일이 없으므로 <strong>추상 클래스를 권장</strong>한다.</li>
<li>코드 구현<pre><code class="language-java">@MappedSuperclass
public class BaseEntity {
private Long id;
private String name;
}
</code></pre>
</li>
</ul>
<p>...</p>
<p>@Entity
public class Member extends BaseEntity {
  ...
}</p>
<p>```</p>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[다양한 연관관계 매핑]]></title>
            <link>https://velog.io/@minmin_key/%EB%8B%A4%EC%96%91%ED%95%9C-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91</link>
            <guid>https://velog.io/@minmin_key/%EB%8B%A4%EC%96%91%ED%95%9C-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91</guid>
            <pubDate>Mon, 23 Aug 2021 06:54:55 GMT</pubDate>
            <description><![CDATA[<h3 id="연관관계-매핑시-고려사항-3가지">연관관계 매핑시 고려사항 3가지</h3>
<h4 id="다중성">다중성</h4>
<ul>
<li>다대일 : <code>@ManyToOne</code></li>
<li>일대다 : <code>@OneToMany</code></li>
<li>일대일 : <code>@OneToOne</code></li>
<li>다대다 : <code>@ManyToMany</code>
(실무에선 &#39;다대다&#39; 관계는 쓰면 안 된다!)</li>
</ul>
<h4 id="단방향-양방향">단방향, 양방향</h4>
<ul>
<li>테이블<ul>
<li>외래 키 하나로 양쪽 조인 가능</li>
<li>사실 방향이라는 개념이 없다. 즉 단방향과 양방향이 동일하다.</li>
</ul>
</li>
<li>객체<ul>
<li>참조용 필드가 있는 쪽으로만 참조 가능</li>
<li>한쪽만 참조하면 단방향</li>
<li>양쪽이 서로 참조하면 양방향 (양방향 = 단방향 2개)</li>
</ul>
</li>
</ul>
<h4 id="연관관계의-주인">연관관계의 주인</h4>
<ul>
<li>테이블은 <strong>외래 키 하나</strong>로 두 테이블이 연관관계를 맺음</li>
<li>객체 양방향 관계는 A-&gt;B, B-&gt;A처럼 <strong>참조가 2개</strong>이다.</li>
<li>참조가 2개이므로 둘중 테이블의 외래 키를 관리할 곳을 지정해야 한다.</li>
<li>연관관계의 주인 : 외래 키를 관리하는 참조</li>
<li>주인의 반대편 : 외래 키에 영향을 주지 않는다. 단순 조회만 가능하다.</li>
</ul>
<h3 id="다대일-n1">다대일 [N:1]</h3>
<h4 id="다대일-단방향">다대일 단방향</h4>
<p>다대일(N:1)에서 <strong>항상 다(N) 쪽에 외래키가 존재</strong>한다.
가장 많이 사용하는 연관관계이고, 반대는 일대다 [1:N] 관계이다. 
<img src="https://images.velog.io/images/minmin_key/post/e8336082-cde9-4064-bba8-1bb82b8064db/image.png" alt=""></p>
<h4 id="다대일-양방향">다대일 양방향</h4>
<p>외래 키가 있는 쪽이 연관관계의 주인이다. 양쪽이 서로 참조하도록 객체를 설계하고, 테이블 관점에서는 단방향과 차이가 없다.
<img src="https://images.velog.io/images/minmin_key/post/da40ee9b-a46d-4c18-b900-7f1483e84b09/image.png" alt=""></p>
<h3 id="일대다-1n">일대다 [1:N]</h3>
<h4 id="일대다-단방향">일대다 단방향</h4>
<ul>
<li><p>먼저 아래 그림을 보면 다대일과 테이블 구조는 동일하다.</p>
</li>
<li><p><strong>객체의 일대다(1:N)에서 일(1)이 연관관계의 주인</strong>이지만 <strong>테이블에서는 다(N) 쪽에 외래 키</strong>가 있다.</p>
</li>
<li><p>객체와 테이블의 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조이다.</p>
<p><img src="https://images.velog.io/images/minmin_key/post/68fe8cbb-9047-40d9-82ab-ef479277844c/image.png" alt=""></p>
</li>
<li><p><code>@JoinColumn</code>을 꼭 사용해야 한다. 그렇지 않으면 조인 테이블
방식을 사용한다. (중간에 테이블을 하나 추가함)</p>
</li>
<li><p>일대다 단방향의 단점</p>
<ul>
<li>코드가 직관적이지 않다.
(Team을 고쳐도 Member 테이블이 Update되는 등)</li>
<li>연관관계 관리를 위해 추가로 UPDATE SQL 실해</li>
</ul>
</li>
<li><p>일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자!</p>
</li>
</ul>
<h4 id="일대다-양방향">일대다 양방향</h4>
<ul>
<li><strong>읽기 전용 필드</strong>를 사용해서 양방향 처럼 사용하는 방법이다.</li>
<li><code>@JoinColumn(insertable=false, updatable=false)</code>를 이용해서 읽기 전용 필드로 만든다.
<img src="https://images.velog.io/images/minmin_key/post/20a18039-e250-4087-b560-77d4365e19c7/image.png" alt=""><ul>
<li>깔끔하게 <strong>다대일 양방향을 사용</strong>하자!</li>
</ul>
</li>
</ul>
<h3 id="일대일-11">일대일 [1:1]</h3>
<h4 id="일대일-관계">일대일 관계</h4>
<ul>
<li><strong>일대일</strong> 관게는 그 반대도 <strong>일대일</strong>이다.</li>
<li>주 테이블이나 대상 테이블 중에 외래 키 선택 가능하다.</li>
<li>외래 키에 데이터베이스 유니크(UNI) 제약 조건을 추가해야 한다.</li>
</ul>
<h4 id="일대일--주-테이블에-외래-키-단방향-양방향">일대일 : 주 테이블에 외래 키 단방향, 양방향</h4>
<ul>
<li>단방향
<img src="https://images.velog.io/images/minmin_key/post/e577348f-5433-4a4c-8f27-aaedb4b28cad/image.png" alt=""></li>
<li>양방향
다대일과 같이 작성하고, 반대편에 mappedBy를 적용하면 된다.
<img src="https://images.velog.io/images/minmin_key/post/eb81d050-c3ad-4122-8ccb-2007d5ddd52b/image.png" alt=""></li>
</ul>
<h4 id="일대일--대상-테이블에-외래-키-단방향-양방향">일대일 : 대상 테이블에 외래 키 단방향, 양방향</h4>
<ul>
<li>단방향 : <strong>JPA에서 지원하지 않는다.</strong></li>
<li>양방향 : 일대일 주 테이블 양방향 매핑 방법과 동일하다.
<img src="https://images.velog.io/images/minmin_key/post/683f56aa-8e59-4d27-9e37-37267788852f/image.png" alt=""></li>
</ul>
<h3 id="다대다-nm">다대다 [N:M]</h3>
<h4 id="다대다">다대다</h4>
<ul>
<li>관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.</li>
<li>연결 테이블을 추가해서 일대다, 다대일 관계로 풀어야 한다.
<img src="https://images.velog.io/images/minmin_key/post/5ebff064-d98d-44f5-9f78-590fe9eb291b/image.png" alt=""></li>
<li><strong>객체는 컬렉션을 사용해서 객체 2개로 다대다 관계가 가능</strong>하다.
(Ex. Member는 Product List, Product는 Member List로 참조 가능)
<img src="https://images.velog.io/images/minmin_key/post/2f780598-3971-4702-b98e-5a48cffee044/image.png" alt=""></li>
<li><code>@JoinTable</code>로 연결 테이블을 지정할 수 있다.</li>
</ul>
<h4 id="다대다-매핑의-한계">다대다 매핑의 한계</h4>
<ul>
<li><strong>편리해 보이지만 실무에서 사용 X</strong></li>
<li>연결 테이블이 단순히 연결만 하고 끝나는 것이 아니라 추가적으로 주문시간, 수량과 같은 데이터가 들어올 수 있다. 또한 의도하지 않은 Query가 추가될 수 있다.</li>
</ul>
<h4 id="한계-극복">한계 극복</h4>
<ul>
<li><strong>연결 테이블용 Entity를 추가</strong> (연결 테이블을 Entity로 승격)</li>
<li><code>@ManyToMany</code> -&gt; <code>@OneToMany</code>, <code>@ManyToOne</code>
<img src="https://images.velog.io/images/minmin_key/post/d6f499b4-1fae-4735-a9ec-d4b1011691b0/image.png" alt=""></li>
</ul>
<p>  <br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[연관관계 매핑 기초 - 양방향 연관관계]]></title>
            <link>https://velog.io/@minmin_key/%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-%EA%B8%B0%EC%B4%88-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@minmin_key/%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-%EA%B8%B0%EC%B4%88-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84</guid>
            <pubDate>Sat, 21 Aug 2021 05:30:19 GMT</pubDate>
            <description><![CDATA[<h2 id="양방향-연관관계와-연관관계의-주인">양방향 연관관계와 연관관계의 주인</h2>
<h3 id="양방향-매핑">양방향 매핑</h3>
<ul>
<li><p>모델링
아래 그림을 보면 객체에서 양방향으로 연관관계를 설정해도 테이블은 단방향과 차이점이 없다. 즉 테이블에서는 방향이라는 개념 없이 외래 키를 이용해서 조인하여 서로의 연관관계를 알 수 있다. 하지만 객체에서 Team이 Member를 참조하기 위해서는 Member의 list가 Team 객체 내에 존재해야 한다.
<img src="https://images.velog.io/images/minmin_key/post/8c8119fa-b4b9-4aaa-8174-681bacd3a65a/image.png" alt=""></p>
</li>
<li><p>양방향 연관관계 코드
Member의 경우 단방향과 동일하다.</p>
<pre><code class="language-java">@Entity
  public class Member {
  ...
  @ManyToOne
  @JoinColumn(name = &quot;TEAM_ID&quot;)
  private Team team;
  ...
}</code></pre>
<p>Team에서는 List를 통해 Member를 참조하게 되고, 이때 <code>mappedBy = &quot;team&quot;</code>을 통해 Member 객체 내의 <code>Team team</code>과 매핑을 해줄 수 있다.</p>
<pre><code class="language-java">@Entity
public class Team {
 ...
 @OneToMany(mappedBy = &quot;team&quot;)
 List&lt;Member&gt; members = new ArrayList&lt;Member&gt;();
 ...
}</code></pre>
<p>이를 통해 아래 코드와 같이 Team에서도 Member를 조회할 수 있다.</p>
<pre><code class="language-java">//조회
Team findTeam = em.find(Team.class, team.getId());
Member findMember = em.find(Member.class, member.getId());
</code></pre>
</li>
</ul>
<p>//Team으로부터 Member정보 조회
int memberSize = findTeam.getMember().size();
//Member로부터 Team을 조회 후 Team에 속한 모든 Member조회
List<Member> members = findMember.getTeam().getMembers();</p>
<pre><code>
### 연관관계의 주인과 mappedBy
#### 객체와 테이블이 관계를 맺는 차이
   + 객체 연관관계 = 2개
       - 회원 -&gt; 팀 연관관계 (단방향)
       - 팀 -&gt; 회원 연관관계 (단방향)
   + 테이블 연관관계 = 1개
       - 회원 &lt;-&gt; 연관관계 (양방향)
+ 객체의 양방향 연관관계
객체의 **양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다.** 즉 객체를 양방향을 참조하려면 **단방향 연관관계를 2개** 만들어야 한다.

+ 테이블의 양방향 연관관계
테이블은 **외래 키 하나**로 두 테이블의 연관관계를 관리한다. 즉 **양쪽으로 조인**할 수 있다.

+ 외래 키 관리
객체 관점에서는 2개의 단방향 연관관계가 존재하지만 테이블 상에서는 하나의 외래 키만 존재한다. 따라서 2개의 연관관계 중 하나가 이 외래 키를 관리해야 한다.
![](https://images.velog.io/images/minmin_key/post/e0adc992-132b-4038-9ece-7957eaf0fae6/image.png)

#### 연관관계의 주인
+ 양방향 매핑 규칙
  - 객체의 두 관계 중 하나를 연관관계의 주인으로 지정
  - **연관관계의 주인만이 외래키를 관리(등록, 수정)**
  - **주인이 아닌 쪽은 읽기만 가능**
  - 주인은 mappedBy 속성 사용 X
  - 주인이 아니면 mappedBy 속성으로 주인 지정
+ 주인은 무엇으로?
  **외래 키가 있는 곳을 주인**으로 정한다. 아래 그림의 경우 Member 테이블에 외래 키가 존재하므로 Member 객체가 연관 관계의 주인이 된다.
   ![](https://images.velog.io/images/minmin_key/post/974511f3-506f-4610-969b-2eebb82b8f5e/image.png)
   연관관계의 주인은 비지니스 적으로 중요한 것이 아닌 설계 상에서 유리한 곳을 주인으로 하는 것이 정석이다.

#### 양방향 매핑 시 주의점
+ 연관관계의 주인에 값을 입력하지 않는 경우
아래 코드와 같이 연관관계의 주인에 값을 입력하지 않을 경우 Member 테이블은 Team을 참조하지 못했으므로 null 값만 존재하게 된다.
```java
  Team team = new Team();
  team.setName(&quot;TeamA&quot;);
  em.persist(team);

  Member member = new Member();
  member.setName(&quot;member1&quot;);

  //역방향(주인이 아닌 방향)만 연관관계 설정
  team.getMembers().add(member);

  em. persist(member);</code></pre><p><img src="https://images.velog.io/images/minmin_key/post/20f7248e-43d4-4b4e-813d-7d1573f1bab5/image.png" alt="">
따라서 반드시 주인에 값을 입력해야 하고, <strong>순수한 객체 관계를 고려해서 항상 양쪽 모두 값을 입력</strong>해야 한다.</p>
<pre><code class="language-java">  ...
  //연관관계의 주인인 member에 값 설정
  member.setTeam(team);
  //team에도 연관관계 설정
  team.getMembers().add(member);
  ...</code></pre>
<p><img src="https://images.velog.io/images/minmin_key/post/f48a1d1f-e378-46d1-9c6b-b30504d7ae99/image.png" alt=""></p>
<ul>
<li>연관관계 편의 메소드를 생성하자.</li>
<li>양방향 매핑 시에 무한 루프를 조심하자.
Ex) toString(), lombok(되도록이면 toString 쓰지 말자), JSON 생성 라이브러리(Controller에서 Entity를 반환하지 말자!, DTO로 변환하여 반환하자)</li>
</ul>
<h4 id="양방향-매핑-정리">양방향 매핑 정리</h4>
<ul>
<li><strong>단방향 매핑만으로도 이미 연관관계 매핑은 완료</strong> 즉 JPA에서 객체와 테이블 설계는 단방향으로도 완료되어야 한다.</li>
<li>양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐이다.</li>
<li>JPQL에서 역방향으로 탐색할 일이 많다.</li>
<li>따라서 단방향 매핑을 잘 해두면 양방향은 필요할 때 추가해도 된다. 이때 테이블에는 영향을 주지 않는다.</li>
<li><strong>연관관게의 주인은 외래 키의 위치를 기준으로 정해야 한다.</strong> 비지니스 로직을 기준으로 주인을 선택하면 안된다.</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[연관 관계 매핑 기초 - 단방향 연관 관계]]></title>
            <link>https://velog.io/@minmin_key/%EC%97%B0%EA%B4%80-%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@minmin_key/%EC%97%B0%EA%B4%80-%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Thu, 19 Aug 2021 12:55:18 GMT</pubDate>
            <description><![CDATA[<h3 id="연관-관계가-필요한-이유">연관 관계가 필요한 이유</h3>
<h4 id="객체를-테이블에-맞추어-모델링">객체를 테이블에 맞추어 모델링</h4>
<ul>
<li><p>예제 시나리오</p>
<ul>
<li>회원과 팀이 있다.</li>
<li>회원은 하나의 팀에만 소속될 수 있다.</li>
<li>회원과 팀은 다대일 관계이다.</li>
</ul>
</li>
<li><p>객체를 테이블에 맞추어 모델링하며 연관관계가 없는 경우
<img src="https://images.velog.io/images/minmin_key/post/2b4c14be-2578-44ca-a78c-09785b519442/image.png" alt="">
위 그림과 같이 MEMBER 테이블은 TEAM 테이블의 TEAM_ID를 FK로 가져와 연관관계가 존재하지만 객체에서는 서로 연관 관계가 존재하지 않는다.</p>
</li>
<li><p>Entity 구현
Member 객체는 Team의 id를 외래키로 가져올 때 참조하는 것 대신 외래키를 그대로 사용하였다.</p>
<pre><code class="language-java">@Entity
public class Member {
  @Id @GeneratedValue
  private Long id;

  @Column(name = &quot;USERNAME&quot;)
  private String name;

  @Column(name = &quot;TEAM_ID&quot;)
  private Long teamId; 
  … 
}

@Entity
public class Team {
  @Id @GeneratedValue
  private Long id;

  private String name; 
  … 
}
</code></pre>
</li>
</ul>
<pre><code>
+ 객체 지향적이지 않다.
Member 객체에 Team의 id를 설정하기 위해서는 Team 객체에서 id 값을 얻어와 직접 주입해주어야 한다.
```java
 //팀저장
 Team team = new Team();
 team.setName(&quot;TeamA&quot;);
 em.persist(team);
 //회원 저장
 Member member = new Member();
 member.setName(&quot;member1&quot;);
 //team의 id를 가져와 직접 주입
 member.setTeamId(team.getId());
 em.persist(member);
 //팀저장
 Team team = new Team();
 team.setName(&quot;TeamA&quot;);
 em.persist(team);
 //회원 저장
 Member member = new Member();
 member.setName(&quot;member1&quot;);
 //team의 id를 가져와 직접 주입
 member.setTeamId(team.getId());
 em.persist(member);</code></pre><p>Member와 Team을 조회하는 경우에도 Member와 Team을 각각 식별자로 조회해야한다.</p>
<pre><code class="language-java"> //조회
 Member findMember = em.find(Member.class, member.getId()); 
 //연관관계가 없음
 Team findTeam = em.find(Team.class, team.getId());</code></pre>
<ul>
<li><p>객체를 테이블에 맞추어 데이터 중심으로 모델링하는 경우 협력 관계를 만들 수 없다.</p>
<ul>
<li><p><strong>테이블은 외래 키로 조인</strong>하여 연관된 테이블을 찾는다.</p>
</li>
<li><p><strong>객체는 참조를 사용</strong>해서 연관된 객체를 찾는다</p>
</li>
<li><p>이렇듯 객체와 테이블 사이에는 큰 차이점이 있다.
<br></br>  </p>
<h3 id="단방향-연관-관계">단방향 연관 관계</h3>
<h4 id="객체-지향-모델링">객체 지향 모델링</h4>
</li>
<li><p>객체의 연관 관계를 사용해서 모델링 하는 경우
Member 객체는 Team의 id가 아닌 Team 그 자체를 참조를 통해 연관 관계가 형성되어 있다.
<img src="https://images.velog.io/images/minmin_key/post/3a1cddc0-8023-481c-96d5-f2af7e601752/image.png" alt="">
코드로 보면 아래와 같이 @ManyToOne을 통해 다대일 관계를 형성한다. </p>
<pre><code class="language-java">@Entity
public class Member {
@Id @GeneratedValue
private Long id;

@Column(name = &quot;USERNAME&quot;)
private String name;
private int age;

@ManyToOne
@JoinColumn(name = &quot;TEAM_ID&quot;)
private Team team;
}</code></pre>
</li>
<li><p>객체 지향적이다.
Member에 Team을 설정해줄 때도 바로 Team을 주입해준다. 다른 Team을 주입하고자 할 때도 마찬가지로 간단하게 가능하다.</p>
<pre><code class="language-java">//팀 저장
Team team = new Team();
team.setName(&quot;TeamA&quot;);
em.persist(team);
</code></pre>
</li>
</ul>
<p>//회원 저장
Member member = new Member();
member.setName(&quot;member1&quot;);
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);</p>
<pre><code>또한 조회를 해줄 때에도 Member 객체에서 바로 Team을 조회 가능하다.
```java
//조회
Member findMember = em.find(Member.class, member.getId()); 
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();</code></pre></li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Entity 매핑]]></title>
            <link>https://velog.io/@minmin_key/Entity-Mapping</link>
            <guid>https://velog.io/@minmin_key/Entity-Mapping</guid>
            <pubDate>Thu, 19 Aug 2021 02:11:57 GMT</pubDate>
            <description><![CDATA[<h3 id="객체와-테이블-매핑--entity-table">객체와 테이블 매핑 : @Entity, @Table</h3>
<h4 id="entity">@Entity</h4>
<ul>
<li><p>@Entity가 붙은 클래스는 JPA가 관리하고, Entity라 한다.</p>
</li>
<li><p>JPA를 사용해서 테이블과 매핑할 클래스는 @Entity를 필수로 사용한다.</p>
</li>
<li><p><strong>주의!</strong></p>
<ul>
<li>기본 생성자 필수 (파라미터가 없는 public 또는 protected 생성자)</li>
<li>final 클래스, enum, interface, inner 클래스 사용 X</li>
<li>DB에 저장할 필드에 final 사용 X</li>
</ul>
</li>
</ul>
<h4 id="table">@Table</h4>
<ul>
<li>Entity와 매핑할 테이블을 지정한다.</li>
</ul>
<h3 id="db-스키마-자동-생성">DB 스키마 자동 생성</h3>
<ul>
<li>DDL을 애플리케이션 실행 시점에 자동 생성</li>
<li>테이블 중심 -&gt; 객체 중심</li>
<li>DB 방언을 활용해서 DB에 맞는 적절한 DDL 생성</li>
<li>이렇게 <strong>생성된 DDL은 개발 단계에서만 사용</strong></li>
<li>이후 운영에서는 이 DDL을 사용하지 않거나, 적절히 다듬어서 사용<h4 id="생성-방법--hibernatehbm2ddlauto">생성 방법 : hibernate.hbm2ddl.auto</h4>
</li>
<li>속성
<img src="https://images.velog.io/images/minmin_key/post/fdb91ede-5c47-4ff3-93a6-21f47fa9ed30/image.png" alt=""><h4 id="주의점">주의점!</h4>
</li>
<li><strong>운영 장비에는 절대 create, create-drop, update를 사용해선 안된다!!</strong></li>
<li>개발 초기 단계 : create 또는 update</li>
<li>테스트 서버 : update 또는 validate 
(여러 사람이 함께 테스트 혹은 개발할 때 create 사용시 기록이 모두 날아감)</li>
<li>스테이징과 운영 서버 : validate 또는 none
(되도록이면 사용하지 말자! alter를 잘못 입력될 경우 시스템 마비될수도...)</li>
</ul>
<h4 id="ddl-생성-기능">DDL 생성 기능</h4>
<ul>
<li>제약 조건 추가, 유니크 제약 조건 추가 등
ex) 회원 이름 : 필수, 10자 초과X
@Column(nullable = false, length = 10)</li>
<li>DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고, JPA의 실행 로직에는 영향을 주지 않는다.</li>
</ul>
<h3 id="필드와-column-매핑">필드와 Column 매핑</h3>
<h4 id="매핑-어노테이션-정리">매핑 어노테이션 정리</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/99f6a1e6-2444-442a-8cf4-e9ebd0a992d6/image.png" alt=""></p>
<h4 id="column">@Column</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/acceecd8-fd44-44b2-8732-5b604c2fbab4/image.png" alt=""></p>
<h4 id="enumerated">@Enumerated</h4>
<ul>
<li>자바 enum 타입을 매핑할 때 시용</li>
<li>속성<ul>
<li>EnumType.ORDINAL : enum 순서를 DB에 저장, <strong>사용 X</strong> 
(유지보수 어려움)</li>
<li>EnumType.STRING : enum 이름을 DB에 저장</li>
<li>Defalut : EnumType.ORDINAL</li>
</ul>
</li>
</ul>
<h4 id="temporal">@Temporal</h4>
<ul>
<li>날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용</li>
<li>최근에는 생략 가능하다.</li>
</ul>
<h4 id="lob">@Lob</h4>
<ul>
<li>지정 가능한 속성이 없다.</li>
<li>매핑하는 필드의 타입이 문자면 CLOB, 나머지는 BLOB 매핑</li>
</ul>
<h4 id="transient">@Transient</h4>
<ul>
<li>필드에 매핑하지 않을 경우 사용</li>
<li>DB에 저장 X, 조회 X</li>
<li>주로 메모리상에서만 임시로 값을 보관하고 싶을 때 사용한다.</li>
</ul>
<h3 id="기본-키-매핑">기본 키 매핑</h3>
<h4 id="기본-키-매핑-방법">기본 키 매핑 방법</h4>
<ul>
<li>직접 할당 : @Id 사용</li>
<li>자동 생성 : @GeneratedValue</li>
</ul>
<h4 id="generatedvalue-전략">@GeneratedValue 전략</h4>
<ul>
<li><p>IDENTITY</p>
<ul>
<li>기본 키 생성을 DB에 위임
<img src="https://images.velog.io/images/minmin_key/post/420d73f0-efdd-4e06-bd98-53bff0a3a885/image.png" alt=""></li>
<li>JPA는 Persistence Context에서 Entity를 관리하기 위해 기본 키가 필요하다. 하지만 IDENTITY는 DB에 들어가고 나서야 기본 키를 알 수 있기 때문에 예외적으로 em.commit() 시점이 아닌 em.persist() 시점에 DB에 INSERT SQL이 실해되고, DB에서 기본키를 조회하여 Persistence Context의 1차 캐시에 추가된다. </li>
</ul>
</li>
<li><p>SEQUENCE</p>
<ul>
<li>DB의 Sequence Object라는 유일한 값을 순서대로 생성하는 특별한 DB Object를 사용한다.</li>
<li>테이블마다 Sequence를 따로 관리하기 위해서 @SequenceGenerator로 매핑할 수 있다.
(이때 allocationSize는 Sequence가 한번 호출될 때 증가하는 수로 Default가 50이다. 이것을 통해 성능 최적화가 이루어 질 수 있다.)
<img src="https://images.velog.io/images/minmin_key/post/c456b406-937e-496b-9c55-6a19c2323d60/image.png" alt=""><ul>
<li>성능 최적화
SEQUENCE 전략은 다음 키 값이 무엇인지 받기 위해 매번 DB서버와 통신을 해야한다. 이것을 allocationSize를 통해 성능 최적화를 할 수 있다. 만약 allocationSize가 50이라면 처음 DB서버와 통신할 때 현재 키 값은 1이고, 다음 키 값은 51로 설정하게 된다. 이후 50번 키까지는 DB서버와 통신 없이 1~50까지 순서대로 배정이 되고, 51번째 키를 받아야 하는 순간 다시 DB서버와 통신하여 100번까지의 키를 할당 받게 된다. 이러한 방법을 통해 DB서버와의 통신을 줄여 성능을 최적화한다.</li>
</ul>
</li>
</ul>
</li>
<li><p>TABLE</p>
<ul>
<li>키 생성 전용 테이블을 만들어 DB의 Sequence를 횽내내는 전략</li>
<li>장점 : 모든 DB에 적용 가능</li>
<li>단점 : 성능이 떨어진다.</li>
<li>테이블 생성
<img src="https://images.velog.io/images/minmin_key/post/22d71ef1-b014-4fbd-9573-f8b9eb672bbe/image.png" alt=""></li>
<li>TableGenerator
<img src="https://images.velog.io/images/minmin_key/post/0b3f98a3-f9cd-4c41-b98b-426ef2dae5d9/image.png" alt=""><h4 id="권장하는-식별자-전략">권장하는 식별자 전략</h4>
</li>
</ul>
</li>
<li><p><strong>기본 키 제약 조건</strong> : null X, 유일, <strong>변하면 안된다.</strong></p>
</li>
<li><p>미래까지 &#39;변하지 않는다&#39;를 만족하는 자연키를 찾기는 어렵다. 따라서 대체키를 사용하자.</p>
</li>
<li><p><strong>권장 : Long형 + 대체키 +  키 생성전략 사용 (AUTO, Sequence Object 등)</strong></p>
</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JPA Persistence Context]]></title>
            <link>https://velog.io/@minmin_key/JPA-Persistence-Context</link>
            <guid>https://velog.io/@minmin_key/JPA-Persistence-Context</guid>
            <pubDate>Mon, 16 Aug 2021 14:38:34 GMT</pubDate>
            <description><![CDATA[<h3 id="entity-manger-factory-entity-manger">Entity Manger Factory, Entity Manger</h3>
<p>아래 그림과 같이 웹 어플리케이션은 EntityManber Factory는 고객의 요청에 따라 EntityManager를 생성한다. 이 EntityManager는 Connection을 통해 DB에 접근하게 된다.
<img src="https://images.velog.io/images/minmin_key/post/25bffacd-3f17-4f63-ac07-a9300ec0304c/image.png" alt=""></p>
<h3 id="persistence-context">Persistence Context</h3>
<ul>
<li>Persistence Context : Entity를 영구 저장하는 환경이다. </li>
<li>Persistence Context는 논리적인 개념으로 Entity Manager를 통해 접근 가능하다. 따라서 Entity Manager가 생성될 때 Persistence Context도 생성되어 Mapping된다.</li>
</ul>
<h3 id="entity의-생명-주기">Entity의 생명 주기</h3>
<ul>
<li>비영속(new/transient) : Persistence Context와 관계없는 <strong>새로운</strong> 상태</li>
<li>영속(managed) : Persistence Context에 <strong>관리</strong>되는 상태</li>
<li>준영속(detached) : Persistence Context에 저장되었다가 <strong>분리</strong>된 상태</li>
<li>삭제(removed) : <strong>삭제</strong>된 상태
<img src="https://images.velog.io/images/minmin_key/post/fccb272f-9b73-448f-a66b-446793e0e106/image.png" alt=""></li>
</ul>
<h4 id="비영속-상태">비영속 상태</h4>
<p>객체가 생성만 되고 Persistence Context에 저장되지 않은 상태이다.</p>
<pre><code class="language-java">//객체 생성
Member member = new Member();
member.setId(&quot;member1&quot;);
member.setUsername(&quot;회원1&quot;);</code></pre>
<p><img src="https://images.velog.io/images/minmin_key/post/bdd97857-97f4-4665-8677-5b3f12dab2a9/image.png" alt=""></p>
<h4 id="영속-상태">영속 상태</h4>
<p>생석된 객체가 Persistence Context에 저장된 상태. 하지만 이때 DB에 저장되는 것은 아니다 DB에 저장되는 시점은 Transaction에 Commit되는 시점이다.</p>
<pre><code class="language-java">...
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장
em.persist(member);</code></pre>
<p><img src="https://images.velog.io/images/minmin_key/post/e1a00031-94b6-4234-80a2-b7e3330b94c8/image.png" alt=""></p>
<h4 id="준영속과-삭제">준영속과 삭제</h4>
<p>준영속은 객체를 Persistence Context에서 분리시킨 상태이고, 삭제는 말 그대로 삭제된 상태이다.</p>
<pre><code class="language-java">...
//객체 분리
em.detach(member);

//객체 삭제
em.remove(member);</code></pre>
<h3 id="persistence-context의-이점">Persistence Context의 이점</h3>
<h4 id="1-1차-캐시">1. 1차 캐시</h4>
<p>Entity Manager가 조회를 요청할 때 먼저 Persistence Context의 1차 캐시에서 조회한다. </p>
<pre><code class="language-java">Member member = new Member();
member.setId(&quot;member1&quot;);
member.setUsername(&quot;회원1&quot;);
//1차 캐시에 저장
em.persist(member)
//1차 캐시에서 조회
Member findMember = em.find(Member.class, &quot;member1&quot;);
</code></pre>
<p><img src="https://images.velog.io/images/minmin_key/post/689b601a-f770-4661-95f6-5719578cfc37/image.png" alt=""></p>
<p>만약 1차 캐시에 없는 값을 조회하는 경우 DB에서 조회하여 1차 캐시에 저장한 후 값을 반환하게 된다.</p>
<pre><code class="language-java">...
Member findMember2 = em.find(Member.class, &quot;member2&quot;);
...</code></pre>
<p><img src="https://images.velog.io/images/minmin_key/post/776eeaaf-075c-432f-b289-fe6708c3ed8d/image.png" alt="">
하지만 고객의 요청이 종료될때 Entity Manager는 삭제되기 때문에 1차 캐시가 성능상 큰 이점을 주지는 않는다.</p>
<h4 id="2-동일성-보장">2. 동일성 보장</h4>
<p>같은 영속 Entity를 읽어올 경우 그것에 대한 동일성을 보장한다.</p>
<pre><code class="language-java">...
Member a = em.find(Member.class, &quot;member1&quot;);
Member b = em.find(Member.class, &quot;member1&quot;);
//동일성 비료 : true
System.out.printIn(a === b);
...</code></pre>
<h4 id="3-entity-등록시-transaction을-지원하는-쓰기-지연transactional-write-behind">3. Entity 등록시 Transaction을 지원하는 쓰기 지연(Transactional write-behind)</h4>
<p>JPA는 Commit을 하기 전까지는 쓰기 지연 SQL 저장소에 쿼리들을 저장하고, Transaction Commit과 함께 밀린 쿼리들을 DB에 전송하게 된다.</p>
<pre><code class="language-java">...
//Transaction 시작
transcation.begin();

em.persist(memberA);
em.persist(memberB);
//현재까지 INSERT SQL을 DB에 보내지 않았다.

//Commit하는 순간 DB에 INSERT SQL을 보낸다.
transaction.commit();
...</code></pre>
<h4 id="4-변경-감지-dirty-check">4. 변경 감지 (Dirty-Check)</h4>
<p>JPA는 Persistence Context 안의 1차 캐시에 Entity의 스냅샷을 저장한다. 이 스냅샷은 DB에서 최초로 읽어온 시점의 상태를 저장한 것이다. </p>
<pre><code class="language-java">...
Member memberA = em.find(Member.class, &quot;member1&quot;);
//Entity Data 수정
memberA.setUsername(&quot;회원2&quot;);
memberA.setAge(10);

transaction.commit();
...</code></pre>
<p>변경 후 Commit 하는 시점에 현재 Entity와 스냅샷을 비교하여 UPDATE SQL을 생성하여 쓰기 지연 SQL 저장소에 저장 후 DB에 전송하게 된다.
<img src="https://images.velog.io/images/minmin_key/post/f46553cb-798c-4bd6-ae9c-57730eef5f41/image.png" alt=""></p>
<h3 id="flush">Flush</h3>
<p>Persistence Context의 변경 내용을 DB에 반영하는 작업이다.</p>
<h4 id="flush-발생-시">Flush 발생 시</h4>
<ul>
<li>변경 감지</li>
<li>수정된 Entity를 쓰기 지연 SQL 저장소에 등록</li>
<li>쓰기 지연 SQL 저장소의 쿼리를 DB에 전송 (등록, 수정, 삭제 쿼리)</li>
<li>1차 캐시의 내용이 삭제되지는 않는다.</li>
</ul>
<h4 id="persistence-context를-flush-하는-방법">Persistence Context를 Flush 하는 방법</h4>
<ul>
<li>em.flush() : 직접 호출</li>
<li>Transaction Commit : Flush 자동 호출</li>
<li>JPQL 쿼리 실행 : Flush 자동 호출</li>
</ul>
<h4 id="유의할-것">유의할 것!</h4>
<ul>
<li>Persistence Context를 비우지 않는다.</li>
<li>Persistence Context의 변경 내용을 DB에 동기화한다.</li>
<li>Transaction이라는 작업 단위가 중요하다. 즉 Commit 직전에만 동기화 하면 된다.</li>
</ul>
<h3 id="준영속-상태">준영속 상태</h3>
<p>영속에서 준영속으로 바뀐 상태로 영속 상태의 Entity가 Persistence Context에서 분리(detached)되어 Persistence Contest가 제공하는 기능(Dirty Check 등)을 사용하지 못한다. </p>
<h4 id="준영속-상태로-만드는-방법">준영속 상태로 만드는 방법</h4>
<ul>
<li>em.detach(entity) : 특정 Entity만 준영속 상태로 전환</li>
<li>em.clear() : Persistence Context를 완전히 초기화</li>
<li>em.close() : Persistence Context를 종료</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/dashboard">https://www.inflearn.com/course/ORM-JPA-Basic/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[싱글톤 컨테이너]]></title>
            <link>https://velog.io/@minmin_key/%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@minmin_key/%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Sun, 16 May 2021 16:30:58 GMT</pubDate>
            <description><![CDATA[<h3 id="싱글톤-패턴">싱글톤 패턴</h3>
<ul>
<li>클래스의 인스턴스가 1개만 생성되는 것을 보장하는 디자인 패턴이다. </li>
<li>아래 코드는 싱글톤 패턴의 예시 코드이다.<pre><code class="language-java">public class Singleton {
  private static final Singleton instance = new Singleton();
      //private 생성자
      private Singleton(){
      }
      //publice으로 만든 함수로 객체 인스턴스가 필요하면 이 static 메소드를 통해서만 조회 가능
      public static Singleton getInstance(){
          return instanc;
      }
}</code></pre>
</li>
<li><code>static</code> 키워드를 사용하여 메모리 할당을 딱 한번만 하게 한다. 따라서 <code>static</code> 영역에 객체를 딱 1개만 생성한다. 또한 <code>final</code> 키워드를 사용하여 값을 변경하는 것도 막는다. 그리고 <code>private 생성자</code>를 통해 외부에서 임의로 new 키워드를 사용하지 못하도록 막는다.</li>
</ul>
<h4 id="싱글톤-패턴의-문제점">싱글톤 패턴의 문제점</h4>
<ul>
<li>싱글톤 패턴을 구현하기 위해 코드가 많이 필요하다.</li>
<li>의존관계상 클라이언트가 Singleton Instance를 만드는 구체 클래스에 의존한다. 따라서 DIP(의존성역전)와 OCP(개방 폐쇄)를 위반한다.</li>
<li>테스트하기 어렵다.</li>
<li>내부 속성을 변경하거나 초기화하는 것이 어려워 유연성이 떨어진다.
<br></br></li>
</ul>
<h3 id="싱글톤-컨테이너">싱글톤 컨테이너</h3>
<ul>
<li>스프링 컨테이너는 위와 같은 싱글톤 패턴의 문제점을 해결하면서 객체 인스턴스를 싱글톤 패턴으로 관리한다. 즉 스프링 빈은 싱글톤으로 관리되는 빈이다.</li>
<li>스프링 컨테이너는 싱글톤 컨테이너 역할을 하고, 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.</li>
<li>따라서 스프링 컨테이너는 DIP, OCP, 테스트, private 생성자라는 단점으로부터 자유롭게 싱글톤을 사용할 수 있다.
<img src="https://images.velog.io/images/minmin_key/post/10110fd5-b5db-4dc2-babd-148736711a13/image.png" alt=""></li>
</ul>
<p><br></br></p>
<h3 id="싱글톤-방식의-주의점">싱글톤 방식의 주의점</h3>
<ul>
<li>싱글톤 방식은 객체 인스턴스를 하나만 생성해서 공유하는 방식이다. 따라서 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지(stateful)하게 설계해서는 안된다.</li>
<li>즉 무상태(stateless)로 설계해야한다.<ul>
<li>특정 클라이언트에 의존적인 필드가 있어선 안된다.</li>
<li>특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.</li>
<li>따라서 읽기만 가능해야한다.</li>
<li>필드 대신 자바에서 공유되지 않는, 지역변수, Parameter, ThreadLocal 등을 사용해야 한다.
<br></br><h3 id="configuration과-싱글톤">@Configuration과 싱글톤</h3>
</li>
</ul>
</li>
<li>스프링 컨테이너는 싱글톤 레지스트리이다. 하지만 스프링이 자바 코드까지 컨트롤하지는 못한다. 따라서 스프링은 클래스의 바이트를 조작하는 라이브러리를 사용하여 스프링 빈이 싱글톤이 되독록 보장해준다.</li>
<li>만약 @Configuration이 적용된 스프링 빈의 정보를 조회한다면 아래와 같다. 
<code>bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd982d120</code></li>
<li>이때 클래스명 이외에 <code>$$EnhancerBySpringCGLIB$$bd982d120</code>와 같은 값이 붙는데 이것은 스프링이 CGLIB라는 바이트 조작 라이브러리를 사용해서 <code>AppConfig</code> 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.</li>
<li>CGLIB는 @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 그 빈을 반환하고, 스프링 빈이 없으면 생성하여 스프링 빈에 등록하고 반환한다. 따라서 싱글톤이 보장된다.</li>
<li>이때 만약 @Configuration이 적용되지 않고 @Bean만을 사용한다면 스프링 빈에는 등록이 되지만 CGLIB가 작동하지 않아 싱글톤이 보장되지 않는다.</li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 : <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard">https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 컨테이너]]></title>
            <link>https://velog.io/@minmin_key/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@minmin_key/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Mon, 10 May 2021 12:32:01 GMT</pubDate>
            <description><![CDATA[<h3 id="스프링-컨테이너">스프링 컨테이너</h3>
<blockquote>
<h5 id="appconfig">AppConfig</h5>
</blockquote>
<pre><code class="language-java">import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService(){
    ...
    }
    @Bean
    public MemberRepository memberRepository() {
    ...
    }
    @Bean
    public OrderService orderService(){
    ...
    }
    @Bean
    private static DiscountPolicy discouontPolicy() {
    ...
    }
}</code></pre>
<blockquote>
<h5 id="orderapp">OrderApp</h5>
</blockquote>
<pre><code class="language-java">import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
...
public class OrderApp(){
    ...
        //apc는 ApplicationContext 인터페이스의 구현체이다.
    ApplicationContext apc = new AnnotationConfigApplicationContext(AppConfig.class);
    MemberService memberService = apc.getBean(&quot;memberService&quot;, MemberService.class);
    OrderService orderService = apc.getBean(&quot;orderService&quot;, OrderService.class);
    ...
}</code></pre>
<ul>
<li><code>ApplicationContext</code>를 스프링 컨테이너라 한다. <code>ApplicationContext</code>은 인터페이스이고 스프링 컨테이너의 최상위 인터페이스인 <code>BeanFactory</code>를 상속받아서 제공한다.</li>
<li>스프링 컨테이너는 XML을 기반으로 만들 수 있고, 매노테이션 기반의 자바 설정 클래스로 만들 수 있다. 위 예시 코드의 <code>AppConfig</code>는 애노테이션 기반의 자바 설정 클래스로 만든 것이다.</li>
<li>스프링 컨테이너는 <code>AnnotationConfigApplicationContext</code> 객체를 통해 <code>@Configuration</code>이 붙은 <code>AppConfig</code>를 설정 정보로 사용한다. 이때 <code>AppConfig</code> 내부의 <code>@Bean</code>이 붙은 메서드를 모두 호출해서 반환된 객
체를 스프링 컨테이너에 등록한다. 그리고 이 객체들을 스프링 빈이라 한다.</li>
<li>스프링 빈은 <code>@Bean</code>이 붙은 메서드의 이름을 스프링 빈의 이름으로 사용하고 이 이름을 인자로 사용하는 <code>applicationContext.getBean(&quot;이름&quot;, 타입)</code> 메서드로 찾을 수 있다.</li>
</ul>
<h3 id="스프링-컨테이너-생성-과정">스프링 컨테이너 생성 과정</h3>
<h4 id="1-스프링-컨테이너-생성">1. 스프링 컨테이너 생성</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/97de5c60-12c7-4197-a4c3-8796478e3406/image.png" alt=""></p>
<ul>
<li><code>new AnnotationConfigApplicationContext(AppConfig.class)</code>를 통해 스프링 컨테이너를 생성해준다. 이때 인자 값으로 구성 정보를 입력해주어야 하는데 이 경우 <code>AppConfig.class</code>를 구성 정보로 넘겨주었다.</li>
</ul>
<h4 id="2-스프링-빈-등록">2. 스프링 빈 등록</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/9b31e810-3941-47c3-9a66-47a5995a0b62/image.png" alt=""></p>
<ul>
<li>스프링 컨테이너는 인자로 넘어온 설정 클래스, 즉 <code>AppConfig</code>의 <code>@Bean</code>이 붙은 메서드들을 스프링 빈 저장소에 이름과 객체 타입으로 등록한다.</li>
</ul>
<h4 id="3-스프링-빈-의존관계-설정">3. 스프링 빈 의존관계 설정</h4>
<p><img src="https://images.velog.io/images/minmin_key/post/9f8831ac-a905-4478-882c-952d5a5a9211/image.png" alt=""></p>
<ul>
<li>스프링 컨테이너는 <code>AppConfig</code>를 확인하고 스프링 빈끼리의 의존 관계를 주입한다. 이것을 DI라고 한다.</li>
</ul>
<h3 id="beanfactory와-applicationcontext">BeanFactory와 ApplicationContext</h3>
<ul>
<li>BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다. 하지만 두가지가 같은 것은 아니다.
<img src="https://images.velog.io/images/minmin_key/post/55fc0d8a-3598-4d39-bf71-80eef09f7021/image.png" alt=""><h4 id="beanfactory">BeanFactory</h4>
</li>
<li>스프링 컨테이너의 최상위 인터테이스로 스프링 빈을 관리하고 조회(<code>getBean()</code>)하는 역할을 담당한다.</li>
</ul>
<h4 id="applicationcontext">ApplicationContext</h4>
<ul>
<li>BeanFactory의 기능을 상속받은 인터페이스로 스프링 빈을 관리하고 조회하는 역할을 수행한다.</li>
<li>애플리케이션을 개발할 때 빈을 관리, 조회 이외에 MessageSource, EnvironmentCapable, EnvironmentCapable, ApplicationEventPublisher, ResourceLoader의 부가기능을 제공한다.</li>
<li>MessageSource : 메세지 소스를 활용하여 국제화 기능, 예를 들면 한국에서는 한국어로, 영어권에서는 영어로 출력하는 기능이다.</li>
<li>EnvironmentCapable : 환경변수, 개발을 할 때는 크게 3가지 환경이 있는데 로컬용, 개발용, 운영용이 있는데 각 환경 별로 구분해서 처리한다.</li>
<li>ApplicationEventPublisher : 애플리케이션 이벤트를 만들고 구독하든 모델을 편리하게 지원한다.</li>
<li>ResourceLoader : 파일, 클래스 패스, 외부 등에서 리소스를 편리하게 조회한다.</li>
</ul>
<h3 id="beandefinition---스프링-빈-설정-메타-정보">BeanDefinition - 스프링 빈 설정 메타 정보</h3>
<ul>
<li>스프링은 자바 config와 xml 등 다양한 설정 형식을 지원한다. 이것이 가능한 이유에는 <code>BeanDefinition</code>이 있다. </li>
<li><code>BeanDefinition</code>은 스프링 빈의 정보를 추상화한 것으로 빈 설정 메타 정보라 한다. 즉 스프링 빈을 역할과 구현을 개념적으로 나눈 것이라 볼 수 있다.</li>
<li>자바 코드를 읽든 xml을 읽든 스프링은 <code>BeanDefinition</code>을 만들고 스프링 컨테이너는 코드가 무엇인지는 상관하지 않고 <code>BeanDefinition</code>만 보면 된다.</li>
<li>스프링 컨테이너는 이 <code>BeanDefinition</code>을 기반으로 스프링 빈을 생성하게 된다.
<img src="https://images.velog.io/images/minmin_key/post/16ec2da4-9eda-496a-813b-de53239e6807/image.png" alt=""></li>
</ul>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 : <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard">https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[IoC, DI, 컨테이너와 컨테이너]]></title>
            <link>https://velog.io/@minmin_key/IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@minmin_key/IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Sat, 01 May 2021 15:31:10 GMT</pubDate>
            <description><![CDATA[<h3 id="iocinversion-of-control--제어의-역전">IoC(Inversion of Control : 제어의 역전)</h3>
<ul>
<li>애플리케이션의 전체 동작 방식을 구성하기 위해 구현 객체를 생성, 연결하는 별동의 설정 클래스인 AppConfig가 있다고 하자.
<img src="https://images.velog.io/images/minmin_key/post/d53f7d63-bf66-4985-a892-ef8050066639/image.png" alt=""></li>
<li>위 그림과 같이 <code>OrderServiceImpl</code>은 필요한 인터페이스들을 AppConfig로 부터 호출하지만 어떤 구현 객체들이 실행될지 알 수 없다. 즉 프로그램의 제어 흐름에 대한 모든 권한은 AppConfig가 가지고 있다.</li>
<li>이 처럼 프로그램의 제어 흐름을 <code>OrderServiceImpl</code>이 직접 제어하는 것이 아닌 AppConfig와 같이 외부에서 관리하는 것을 IoC(제어의 역전)이라고 한다.</li>
</ul>
<h4 id="프레임-워크와-라이브러리">프레임 워크와 라이브러리</h4>
<ul>
<li>아래 코드는 프레임 워크인 JUnit을 사용한 코드이다. 내가 작성한 코드는 <code>beforeEach()</code>와 <code>join()</code> 뿐이지만 이 코드들을 <code>@Test</code>와 <code>@BeforeEach</code>를 통해 제어하고, 대신 실행한다. 즉 프레임 워크는 내가 작성한 코드를 제어하고, 그것을 대신 실행한다.</li>
</ul>
<blockquote>
</blockquote>
<pre><code>import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
...
    @BeforeEach
    public void beforeEach(){
        ...
    }
    @Test
    void join(){
        ...
    }
...</code></pre><ul>
<li>라이브러리는 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 라이브라리이다. 예를 들어 내가 코드로 html을 xml로 바꾸는 것을 호출한다면 내 코드가 호출하는 것이므로 그것은 라이브러리이다</li>
</ul>
<h3 id="didependecy-injection--의존관계-주입">DI(Dependecy Injection : 의존관계 주입)</h3>
<ul>
<li>의존관계는 정적인 클래스 의존 관계와 실행 시점(런타임)에 결정되는 동적인 객체 의존 관계로 나뉜다.</li>
</ul>
<blockquote>
<p><strong>정적</strong>인 클래스 의존 관계
클래스가 사용하는 import 코드만 보고도 의존 관계를 쉽게 판단할 수 있다. 즉 애플리케이션을 실행하지 않아도 분석 가능하다.</p>
</blockquote>
<blockquote>
<p><strong>동적</strong>인 객체 인스턴스 의존 관계
애플리 케이션 실행 시점에 생성돈 객체 인스턴스의 참조가 연결된 의존관계이다.</p>
</blockquote>
<ul>
<li>의존관계 주입이란 애플리케이션 실행 시점(런타임)에 AppConfig와 같은 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 의존 관계를 연결시키는 것이다.</li>
<li>의존관계 주입을 사용하면 정적인 클래스 의존 관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.</li>
</ul>
<h3 id="컨테이너">컨테이너</h3>
<p>Appconfig와 같이 객체를 생성하고 관리하면서 의존 관계를 연결해 주는 것을 IoC 컨테이너 또는 DI 컨테이너라 한다.
주로 DI 컨테이너라 하지만 어셈블러, Object Factory 등으로 불리기도 한다.</p>
<p><br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 : <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard">https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] final이란?]]></title>
            <link>https://velog.io/@minmin_key/Java-final%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@minmin_key/Java-final%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 25 Apr 2021 11:25:06 GMT</pubDate>
            <description><![CDATA[<p>final 키워드는 entity를 딱 한번만 할당하는 것이다. 따라서 다시 할당하는 경우 error가 발생한다. final은 class, 메소드, 변수에 붙일 수 있고, 각 기능이 다르다.</p>
<h3 id="1-final-class">1. final class</h3>
<ul>
<li>class 앞에 final 키워드를 붙이면 해당 class는 상속되지 않는다.<blockquote>
<pre><code class="language-java">public final class Fruit{
 ...
}
public class Apple extends Fruit { ... }    // error 발생</code></pre>
</blockquote>
</li>
</ul>
<h3 id="2-final-메소드">2. final 메소드</h3>
<ul>
<li>메서드 앞에 final 키워드를 붙이면 해당 메소드는 더 이상 Overriding 할 수 없다.</li>
<li>메소드 Overriding : 부모 class에서 이미 정의된 메소드를 자식 class에서 같은 이름을 가진 메소드로 재정의하는 것을 말한다.<blockquote>
<pre><code class="language-java">public final class Parent{
 protected final int getGrade() {...}
}
class Child extends Parent { 
  protected int getGrade() {...}    // error 발생
}</code></pre>
</blockquote>
</li>
</ul>
<h3 id="3-final-변수">3. final 변수</h3>
<ul>
<li>변수 앞에 final 키워드를 붙이면 해당 변수는 변경될 수 없다. 따라서 반드시 초기값을 정해줘야한다. 이때 원시변수일 때와 참조변수일 때 차이가 있다. <ul>
<li>원시 변수에 적용 시 : 해당 변수는 값을 변경할 수 없다.</li>
<li>참조 변수에 적용 시 : 참조 변수가 heap 내의 다른 객체를 가리키도록 변경할 수 없다.<blockquote>
<pre><code class="language-java">public final class Parent{
final int childNum = 4;    //반드시 초기값 설정
void getBaby(){
 childNum++;        //error 발생
}
}</code></pre>
</blockquote>
</li>
</ul>
</li>
</ul>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p><a href="https://gmlwjd9405.github.io/2018/08/06/java-final.html">https://gmlwjd9405.github.io/2018/08/06/java-final.html</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[HashTable, HashMap, ConCurrentHashMap 차이]]></title>
            <link>https://velog.io/@minmin_key/HashTable-HashMap-ConCurrentHashMap-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@minmin_key/HashTable-HashMap-ConCurrentHashMap-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Sun, 25 Apr 2021 10:45:31 GMT</pubDate>
            <description><![CDATA[<p>HashTable, HashMap, ConCurrentHashMap은 기본적으로 Map 인터페이스를 구현한 클래스이다. Map 인터페이스는 키(key)와 값(value)로 데이터를 관리하며 키를 이용하여 데이터를 추출할 수 있다.</p>
<h3 id="separate-chaning-open-addressing">Separate Chaning, Open Addressing</h3>
<ul>
<li>Hash의 기본적인 구조는 key를 hash function을 통해 특정 값으로 변환 후 그 값에 맞는 index를 가진 bucket안에 value를 넣어주는 구조이다. 하지만 넣어주려는 bucket에 이미 값이 있는 경우 충돌을 처리하는 방법에는 2가지 방법이 있다. Separate Chaning와 Open Addressing이다.</li>
<li>Separate Chaning
Separate Chaning 방식은 bucket이 list의 포인터를 저장하고 있고, value는 linked list의 헤드에 저장된다. 만약 충돌이 발생했을시 linked list의 헤드의 앞에 추가하는 식으로 구현된다. 하지만 worst case로 한 bucket에만 저장되는 경우 마지막 데이터는 O(N)의 속도를 가지게 되는데 이 문제는 Java 8에서 Red-Black 트리를 사용하여 worst case에도 O(logN)로 탐색이 가능하다</li>
<li>Open Addressing
Open Addressing 방식은 bucket에 value를 저장하는 방식이다. 만약 충돌이 발생하면 비어있는 bucket을 찾는 탐색을 하고 빈 bucket에 value를 넣어준다. 탐색 방법에는 Linear Probing, Qudratic Probing, Double Hashing이 있다.<pre><code>  - Linear Probing : 충돌 발생 지점부터 +1씩 bucket을 탐색한다. 주변의 bucket이 전부 차있는 Primary Clustering 문제가 있다. 캐싱에는 유리하지만 bucket이 가득찰 경우 효율은 급격하게 감소한다.
  - Qudratic Probing : Primary Clustering을 개선하기 위한 방법으로 충돌 발생 지점부터 n&lt;sup&gt;2&lt;/sup&gt;씩 증가시켜 탐색한다. 하지만 초기 hash값이 동일하다면 탐색 과정이 동일하다는 Secondary Clustering 문제가 있다.
  - Double Hashing : 위의 탐색방법들은 규칙성이 생겨 Clustering 문제가 생긴다 따라서 규칙성을 없애기 위해 2차 Hash Function을 이용하여 다음 탐색을 정하게 된다.</code></pre></li>
</ul>
<h3 id="1-hashtable">1. HashTable</h3>
<ul>
<li>HashTable의 모든 Data 변경 메소드는 syncronized로 선언되어 있다. 따라서 메소드 호출 전 thread간 동기화 lock을 통해 multi thread 환경에서도 data의 무결성을 보장한다. 하지만 이 동기화 락이 매우 느린 동작이어서 단일 thread 환경에서는 HashMap을 사용하는 것이 훨씬 빠르다.</li>
</ul>
<h3 id="2-hashmap">2. HashMap</h3>
<ul>
<li>HashMap은 HashTable과 동일한 내부 구조를 가지고 있지만 HashTable은 syncronized 키워드가 없기 때문에 동기화가 보장되지 못한다. 하지만 동기화 처리를 하지 않기 때문에 value를 찾는 속도는 상당히 빠르다. 또한 HashTable과는 다르게 key와 value가 null값을 허용한다.</li>
<li>HashMap은 충돌 문제를 Separate Chaning을 사용하여 처리한다. 또한 worst case 문제는 java8에서 bucket에 적은 data라면 linked list를 사용하지만 많은 data가 쌓이면 Red-Black tree로 변환한다. 따라서 worst case에도 O(logN)의 속도를 보장한다.</li>
</ul>
<h3 id="3-concurrenthashmap">3. ConCurrentHashMap</h3>
<ul>
<li>HashMap과 같은 구조이지만 동기화가 보장되지 않는 HashMap을 보완한 것이 ConcurrentHashMap이다. 하지만 HashMap과는 다르게 key와 value가 null값을 허용하지 않는다.</li>
</ul>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p><a href="https://velog.io/@agugu95/Hash-Table-Java-HashMap">https://velog.io/@agugu95/Hash-Table-Java-HashMap</a>
<a href="https://limkydev.tistory.com/40">https://limkydev.tistory.com/40</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java Enum 클래스]]></title>
            <link>https://velog.io/@minmin_key/Java-Enum-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@minmin_key/Java-Enum-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sun, 25 Apr 2021 09:29:24 GMT</pubDate>
            <description><![CDATA[<h3 id="1-enum-클래스">1. Enum 클래스</h3>
<p>자바에서는 enum을 사용하여 열거체를 사용할 수 있다. 열거체란 말 그대로 변수들을 나열한 것을 말한다.</p>
<h3 id="2-문법">2. 문법</h3>
<blockquote>
</blockquote>
<p>문법</p>
<pre><code>enum 열거체이름 { value1, value2, value3 , ... }</code></pre><p>예시</p>
<pre><code>enum Fruit { Apple, Orange, Peach, ... }</code></pre><h3 id="3-자바-enum의-장점">3. 자바 enum의 장점</h3>
<ul>
<li>열거체를 비교할때 실제 값뿐만 아니라 type까지 체크한다.</li>
<li>열거체의 변수값이 바뀌어도 다시 컴파일하지 않아도 된다.</li>
</ul>
<h3 id="4-대표-메소드">4. 대표 메소드</h3>
<ul>
<li>static E values() : 열거체 모든 변수를 가지는 배열을 생성 후 반환한다.</li>
<li>static E valueOf(String name) : 인자와 일치하는 열거체의 변수를 반환한다.</li>
<li>int ordinal() : 열거체 변수의 index값을 반환한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[좋은 객체 지향 프로그래밍이란?]]></title>
            <link>https://velog.io/@minmin_key/%EC%A2%8B%EC%9D%80-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@minmin_key/%EC%A2%8B%EC%9D%80-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 25 Apr 2021 08:56:34 GMT</pubDate>
            <description><![CDATA[<h3 id="객체-지향-특징">객체 지향 특징</h3>
<ul>
<li>추상화</li>
<li>캡슐화</li>
<li>상속</li>
<li><strong>다형성</strong></li>
</ul>
<h3 id="객체-지향-프로그래밍">객체 지향 프로그래밍</h3>
<ul>
<li><p>객체 지향 프로그래밍이란 프로그램을 여러 개의 독립된 단위인 &#39;<strong>객체</strong>&#39;들의 <strong>모임</strong>으로 보는 것이다. 각각의 객체는 메세지를 주고받고, 데이터를 처리하며 <strong>협력</strong>한다. </p>
</li>
<li><p>객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프트웨어 개발에 많이 사용된다. 이때 프로그램을 유연하고 변경이 용이하게 만든다는 것은 <strong>컴포넌트</strong>를 마치 컴퓨터 부품을 갈아 끼우듯이 쉽고 유연하게 변경하면서 개발하는 것을 말한다.</p>
</li>
</ul>
<blockquote>
<p><strong>컴포넌트</strong> : 소프트웨어 시스템에서 독립적인 기능을 하는 모듈이다. 이때 컴포넌트는 객체, 클래스와는 다른 개념이다. 컴포넌트는 꼭 클래스나 객체로 만들어야만 하는 것도 아니고, 하나의 클래스로 구성되어야 하는 것도 아니다. 즉 하나의 컴포넌트는 하나 이상의 클래스들로 구성될 수 있다.</p>
</blockquote>
<h3 id="다형성">다형성</h3>
<ul>
<li><p>다형성은 객체 지향의 핵심이다. 다형성을 실세계에 비유하면 세상을 역활과 구현으로 구분하는 것이다.<img src="https://images.velog.io/images/alsrl8259/post/a5a66702-51f0-4fe6-9b2f-1099054a410c/KakaoTalk_20210421_215600850.png" alt="">
위 그림을 보면 자동차의 역할을 하는 인터페이스를 사용하여 K3, 아반떼 등 자동차를 구현하면 클라이언트인 운전자는 자동차의 운전방법만 알면 모든 차를 운전할 수 있다. 즉 클라이언트는 구현 대상의 내부 구조를 몰라도 되고, 내부 구조가 변경되거나 구현 대상 자체가 변경되어도 영향을 받지 않는다. 이처럼 <strong>역할</strong>과 <strong>구현</strong>으로 구분하면 세상이 <strong>단순</strong>해지고, <strong>유연</strong>해지며 <strong>변경</strong>도 편리해진다.</p>
</li>
<li><p>자바 언어에 다형성을 적용하면 역할 = 인터페이스, 구현 = 인터페이스를 구현한 클래스, 구현 객체로 분류할 수 있다. 이때 오버라이딩을 통해 인터페이스를 구현한 객체를 실행 시점에 유연하게 변경할 수 있다.</p>
</li>
<li><p>다형성의 본질은 클라이언트를 변경하지 않고, 서버의 구현 기능을 우연하게 변경할 수 있는것이다.</p>
</li>
</ul>
<h3 id="좋은-객체-지향-설계의-5가지-원칙-solid">좋은 객체 지향 설계의 5가지 원칙 (SOLID)</h3>
<h4 id="1-srp-단일-책임-원칙">1. SRP 단일 책임 원칙</h4>
<ul>
<li>한 클래스는 하나의 책임만을 가진다는 원칙이다. 이때 &#39;하나의 책임&#39;이라는 개념이 모호한데 중요한 기준은 &#39;변경&#39;이다. 특정 클래스를 변경하였을 때 그로인한 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이다.</li>
<li>책임의 범위를 잘 조절하는 것이 중요한데 책임의 범위가 너무 작을 경우 기능이 너무 쪼깨지게 되고, 범위가 커질 경우 단일 책임 원칙에 위배되기 때문이다. 이처럼 책임의 범위를 적절히 조절하는 것이 객체 지향의 묘미이다.</li>
</ul>
<h4 id="2-ocp-개방-폐쇄-원칙-가장-중요한-원칙">2. OCP 개방-폐쇄 원칙 (가장 중요한 원칙)</h4>
<ul>
<li>소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다는 원칙이다. 확장을 할 때는 다형성을 활용하여 인터페이스를 구현한 새로운 클래스를 만드는 방법 등으로 가능하다.</li>
<li>문제점 : 구현 객체를 변경하기 위해서는 코드를 변경해야한다. 때문에 다형성을 사용하였지만 OCP 원칙을 지킬 수 없게 된다. 이러한 문제를 해결하기 위해 객체를 생성하고, 연관 관게를 맺어주는 조립, 설정자가 필요하고 바로 스프링 컨테이너가 이 역할을 하게 된다.</li>
</ul>
<h4 id="3-lsp-리스코프-치환-원칙">3. LSP 리스코프 치환 원칙</h4>
<ul>
<li>프로그램의 객체는 프로그램의 정확성을 깨트리지 않으면서 하위 타입의 인스턴스로 바꿔야 한다는 원칙이다. 이 때문에 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다. 예를 들면 자동차라는 인터페이스를 구현한 K3에서 엑셀을 밟으면 후진을 하는 기능을 넣는 경우 규약을 어기게 되므로 LSP 원칙이 깨지게 된다.</li>
</ul>
<h4 id="4-isp-인터페이스-분리-원칙">4. ISP 인터페이스 분리 원칙</h4>
<ul>
<li>특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다. 따라서 특정 인터페이스 자체가 변경되어도 클라이언트에 영향을 주지 않게 된다.</li>
<li>이를 통해 인터페이스가 명확해지고, 대체 가능성이 높아진다.</li>
</ul>
<h4 id="5-dip-의존관계-역전-원칙-중요">5. DIP 의존관계 역전 원칙 (중요)</h4>
<ul>
<li>구현 클래스에 의존하지 않고, 인터페이스에 의존하라는 원칙이다. 즉 다형성에서 구현보다는 역할에 의존해야 한다는 것이다.</li>
<li>하지만 아래 코드와 같이 MemberService 클라이언트가 구현 클래스를 직접 선택하게 되고, MemberService는 인터페이스에 의존하지만, 구현 클래스도 동시에 의존하게 된다. 때문에 DIP를 위반하게 된다.<pre><code class="language-java">public class MemberService {
  private MemberRepository m = new MemoryMemberRepository();
}</code></pre>
</li>
</ul>
<h4 id="정리">정리</h4>
<ul>
<li>객체 지향의 핵심은 다형성</li>
<li>다형성만으로는 OCP, DIP를 지킬 수 없다.</li>
</ul>
<h3 id="객체-지향-설계와-스프링">객체 지향 설계와 스프링</h3>
<ul>
<li>객체 지향 프로그래밍에서 다형성 + OCP, DIP를 가능하게 하기 위해 스프링이 개발되었다. 스프링은 DI(Dependency Injection: 의존관계, 의존성 주입) 컨테이너를 제공함으로써 OCP, DIP를 가능하게 지원한다. 이를 통해 클라이언트 코드의 변경 없이 기능을 확장하고, 쉽게 부품을 교체하듯이 개발을 할 수 있게 되었다.</li>
</ul>
<h3 id="최종-정리">최종 정리</h3>
<ul>
<li>모든 설계에 역할과 구현을 분리하여야 한다.</li>
<li>애플리케이션 설계는 다형성 뿐만 아니라 OCP, DIP를 지켜 언제든지 유연하게 변경할 수 있도록 만드는 것이 좋은 객체 지향 설계이다. 이를 위해 스프링 컨테이너를 이용한다.</li>
<li>이상적으로는 모든 설계에 인터페이스를 부여하자. 예를 들면 어떤 DB를 쓸지 정해지지 않은 상황에서 개발해야 하는 경우 인터페이스를 먼저 만들어 놓으면 구현 단계의 선택을 뒤로 미루고 개발할 수 있다. 이처럼 확장과 변경이 용이하다. 하지만 인터페이스를 남발하면 추상화라는 비용이 발생한다. 코드가 추상화되면 구현 코드를 한번에 알아보지 못하고 인터페이스까지 들어가서 확인해야 코드를 이해할 수 있게 된다. 따라서 기능을 확장할 가능성이 없으면, 구체 class를 직접 사용하고, 나중에 필요한 경우 인터페이스를 도입하는 것이 좋다.</li>
</ul>
<p></br></br></p>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 : <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard">https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring이란?]]></title>
            <link>https://velog.io/@minmin_key/Spring%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@minmin_key/Spring%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 25 Apr 2021 08:55:25 GMT</pubDate>
            <description><![CDATA[<h3 id="1-spring-생태계">1. Spring 생태계</h3>
<ul>
<li>필수 : Spring 프레임워크, Spring 부트</li>
<li>선택 : Spring 데이터, Spring 배치, Spring 세션, Spring 클라우드 등</li>
</ul>
<h3 id="2-spring-부트">2. Spring 부트</h3>
<ul>
<li>Spring을 편리하게 사용할 수 있도록 지원</li>
<li>Tomcat 같은 웹 서버를 내장하는 방법으로 단독으로 실행할 수 있는 Spring 어플리케이션을 쉽게 생성</li>
</ul>
<h3 id="3-스프링의-핵심">3. 스프링의 핵심</h3>
<ul>
<li>Spring은 자바 언어 기반의 프레임워크</li>
<li>자바 언어의 가장 큰 특징은 <strong>객체 지향 언어</strong>라는 것이다.</li>
<li>Spring은 객체 지향 언어가 가진 강력한 특징을 살려내어 좋은 객체 지향 어플리케이션을 개발할 수 있게 도와주는 프레임워크이다.
</br></br></li>
</ul>
<h3 id="reference">[Reference]</h3>
<blockquote>
<p>Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 : <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard">https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>