<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>무럭무럭 성장일기</title>
    <link>https://jineey-dev.tistory.com/</link>
    <description>Develop with jineey</description>
    <language>ko</language>
    <pubDate>Tue, 14 Jul 2026 05:53:21 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>지니(jineey)</managingEditor>
    <image>
      <title>무럭무럭 성장일기</title>
      <url>https://tistory1.daumcdn.net/tistory/7405712/attach/4d1ea1ddbe2c4ae2b7f260d84e30f4f4</url>
      <link>https://jineey-dev.tistory.com</link>
    </image>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #11</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-11</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 6.1 다대일 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 6.2 일대다 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 6.3 일대일[1:1] ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 6.4 다대다[N:N] ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 6.5 정리 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp; 개요&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티의 연관관계를 매핑할 때는 다음 3가지를 고려 필요&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중성&lt;/li&gt;
&lt;li&gt;단방향, 양방향
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향: 객체 관계에서 한 쪽만 참조하는 것&lt;/li&gt;
&lt;li&gt;양방향: 양쪽이 서로 참조하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연관관계의 주인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외래 키를 가진 테이블과 매핑한 엔티티가 연관관계의 주인&amp;nbsp;&lt;/li&gt;
&lt;li&gt;연관관계의 주인이 아닐 경우, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;mappedBy&lt;/span&gt; 속성을 사용하여 연관관계의 주인 필드 이름을 값으로 입력&lt;/li&gt;
&lt;li&gt;연관관계의 다중성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다대일 (@ManyToOne)&lt;/li&gt;
&lt;li&gt;일대다 (@OneToMany)&lt;/li&gt;
&lt;li&gt;일대일 (@OneToOne)&lt;/li&gt;
&lt;li&gt;다대다 (@ManyToMany)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp; 다대일&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 테이블의 일(1), 다(N) 관계에서 외래 키는 항상 다(N)쪽에 있음 ➡️ 객체 양방향 관계에서 &lt;b&gt;연관관계의 주인&lt;/b&gt;은 항상 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;다쪽&lt;/span&gt;&lt;/b&gt;!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. &lt;b&gt;다대일 단방향[N:1]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731849318886&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column (name=&quot;MEMBER_ID&quot;)
    private Long id;
    
    private String username;
    
    @ManyToOne
    @JoinColumn(name=&quot;TEAM_ID&quot;)
    private Team team;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 회원은 Member.team 으로 팀 엔티티를 참조할 수 있지만 반대로 팀은 회원을 참조하는 필드가 없기 때문에 다대일 단방향 연관관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. &lt;b&gt;다대일 양방향[N:1, 1:N]&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;양방향은 외래 키가 있는 쪽이 연관관계의 주인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 외래 키를 관리할 때 연관관계의 주인만 사용&lt;/li&gt;
&lt;li&gt;주인이 아닌 경우는 조회을 위한 JPQL이나 객체 그래프를 탐색할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;양방향 연관관계는 항상 서로를 참조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어느 한 쪽만 참조하면 양방향 연관관계가 성립하지 않음&lt;/li&gt;
&lt;li&gt;항상 서로를 참조하게 할 때는 '연관관계 편의 메소드'를 작성하는 것이 좋으나,&lt;br /&gt;편의 메소드를 한 곳에만 작성하는 것이 아닌 양쪽 다 작성 시 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;무한루프&lt;/span&gt;에 빠지는 것을 주의해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp; 일대다&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일대다 관계는 다대일 관계의 반대 방향.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션인 Collection, List, Set, Map 중에서 하나를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. &lt;b&gt;일대다 단방향[1:N]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 팀은 여러 회원을 참조 가능할 때 일대다 관계라고 칭하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀은 회원들을 참조하지만 반대로 회원은 팀을 참조하지 않으면 둘의 관계는 단방향이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대다 단방향 팀 엔티티&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731849771899&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Team {
    @Id @GeneratedValue
    @Column(name=&quot;TEAM_ID&quot;)
    private Long id;
    
    private String name;
    
    @OneToMany
    @JoinCloumn(name=&quot;TEAM_ID&quot;) //Member 테이블의 TEAM_ID (FK)
    private List&amp;lt;Member&amp;gt; members = new ArrayList&amp;lt;Member&amp;gt;();
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대다 단방향 회원 엔티티&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731849828184&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name=&quot;MEMBER_ID&quot;)
    private Long id;
    
    private String username;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 일대다 단방향 관계를 매핑할 때는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;@JoinColumn&lt;/span&gt; 명시해야 함. 사용하지 않을 시 JPA는 연결 테이블을 중간에 두고 연관관계를 관리하는 조인 테이블 전략을 기본으로 사용하여 매핑함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대다 단방향 매핑 단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매핑한 객체가 관리하는 외래 키가 다른 테이블에 있음&lt;/li&gt;
&lt;li&gt;다른 테이블에 외래 키가 있으면 연관관계 처리를 위해서 INSERT SQL 실행 이후, UPDATE SQL을 추가로 실행 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다대일 양방향 매핑 권장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대다 단방향 매핑 사용 시 엔티티를 매핑한 테이블이 아닌 다른 테이블의 외래 키를 관리 필요&lt;/li&gt;
&lt;li&gt;성능 문제 및 관리의 어려움 발생&lt;/li&gt;
&lt;li&gt;다대일 양방향 매핑을 사용하여 관리해야 하는 외래 키가 본인 테이블에 있도록 하면 문제 해결됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;일대다 양방향[1:N, N:1]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽을 연관관계의 주인으로 설정했을 때, 일대다 양방향 매핑은 존재하지 않으며 다대일 양방향 매핑을 사용해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일대다 양방향 매핑을 해야 할 경우에는 일대다 단방향 매핑 반대편에 &lt;b&gt;같은 외래 키를 사용하는 다대일 단방향 매핑&lt;/b&gt;을 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;읽기 전용&lt;/span&gt;&lt;/b&gt;으로 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731851445073&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name=&quot;MEMBER_ID&quot;)
    private Long id;
    private String username;
    
    @ManyToOne
    @JoinColumn(name=&quot;TEAM_ID&quot;, insertable=false, updatable=false)
    private Team team;
    
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ insertable = false, updatable = false 를 통해 읽기만 가능하도록 설정&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp; 일대일 [1:1]&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일대일 관계는 양쪽이 서로 하나의 관계만 가짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일대일 관계는 주 테이블이나 대상 테이블 중에 누가 외래 키를 가질지 선택 필요&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주 테이블의 외래 키
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주 테이블에 외래 키를 두고 대상 테이블을 참조&lt;/li&gt;
&lt;li&gt;외래 키를 객체 참조와 비슷하게 사용할 수 있기 때문에 객체지향 개발자들이 선호하는 방법&lt;/li&gt;
&lt;li&gt;주 테이블이 외래 키를 가지고 있으므로 주 테이블만 확인해도 대상 테이블과의 연관관계를 알 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;대상 테이블에 외래 키
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적인 데이터베이스 개발자들이 선호하는 방법&lt;/li&gt;
&lt;li&gt;테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지 가능&lt;/li&gt;
&lt;li&gt;단방향 vs 양방향
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향 관계를 JPA 에서 지원하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;양방향
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대일 매핑에서 대상 테이블에 외래 키를 두고 싶으면 양방향으로 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프록시를 사용할 때 외래 키를 직접 관리하지 않는 일대일 관계는 지연 로딩으로 설정해도 즉시 로딩됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp; 다대다 [N:N]&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. &lt;b&gt;단방향&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없기 때문에&amp;nbsp;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용하지만 객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731852865454&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id @Column(name=&quot;MEMBER_ID&quot;)
    private String id;
    
    private String username;
    
    @ManyToMany
    @JoinTable(name=&quot;MEMBER_PRODUCT&quot;, 
               JoinTable = @JoinColumn(name=&quot;MEMBER_ID&quot;),
               inverseJoinColumns = @JoinColumn(name=&quot;PRODUCT_ID&quot;))
    private List&amp;lt;Product&amp;gt; products = new ArrayList&amp;lt;Product&amp;gt;();
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;@JoinTable.name&lt;/span&gt;&lt;br /&gt;연결 테이블을 지정&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;@JoinTable.joinColumns&lt;/span&gt;&lt;br /&gt;현재 방향인 회원과 매핑할 조인 컬럼 정보 지정&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;@JoinTable.inverseJoinColumn&lt;/span&gt;&lt;br /&gt;반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ @ManyToMany로 매핑 시, 다대다 관계를 사용할 때 연결 테이블을 신경쓰지 않아도 되기 때문에 복잡한 다대다 관계를 애플리케이션에서는 아주 단순하게 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. &lt;b&gt;양방향&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역방향 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731853171123&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Product {
    @Id
    private String id;
    
    @ManyToMany(mappedBy = &quot;products&quot;) //역방향 추가
    private List&amp;lt;Member&amp;gt; members;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역방향 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731853298636&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void findInverse(){
    Product product = em.find(Product.class, &quot;productA&quot;);
    List&amp;lt;Member&amp;gt; members = product.getMembers();
    for(Member member : members){
        System.out.println(&quot;member = &quot; + member.getUsername());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3. &lt;b&gt;다대다: 매핑의 한계와 극복, 연결 엔티티 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ManyToMany를 사용하면 연결 테이블을 자동으로 처리해주기 때문에 도메인 모델이 단순해지고 편리해진다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 컬럼이 추가되면 더는 @ManyToMany를 사용할 수 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼들을 매핑해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복합 기본키 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Id : 기본 키를 매핑&lt;/li&gt;
&lt;li&gt;@JoinColumn : 외래 키를 매핑&lt;/li&gt;
&lt;li&gt;@Id + @JoinColumn 을 동시에 사용하여 기본키 + 외래 키 한번에 매핑&lt;/li&gt;
&lt;li&gt;@IdClass : 복합 기본키 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JPA에서 복합 키 사용 시 별도의 식별자 클래스 생성 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복합 키는 별도의 식별자 클래스로 만들어야 함&lt;/li&gt;
&lt;li&gt;Serializable 구현 필요&lt;/li&gt;
&lt;li&gt;equals와 hashCode 메소드 구현 필요&lt;/li&gt;
&lt;li&gt;기본 생성자 필요&lt;/li&gt;
&lt;li&gt;식별자 클래스는 public 이어야 함&lt;/li&gt;
&lt;li&gt;@IdClass를 사용하는 방법 외에 @EmbeddedId 사용하는 방법도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;식별관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 테이블의 기본 키를 받아서 자신의 기본 키 + 외래 키로 사용하는 것&lt;/li&gt;
&lt;li&gt;데이터베이스 용어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;다대다: 새로운 기본 키 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에서 자동으로 생성해주는 대리 키를 Long 값으로 사용하는 것을 기본 키 생성 전략으로 추천함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간편함&lt;/li&gt;
&lt;li&gt;거의 영구히 사용 가능&lt;/li&gt;
&lt;li&gt;비즈니스에 의존하지 않음&lt;/li&gt;
&lt;li&gt;ORM 매핑 시 복합 키를 만들지 않아도 되므로 간단히 매핑 완성 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;다대다  연관관계 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;식별관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;받아온 식별자를 기본 키 + 외래 키로 사용&lt;/li&gt;
&lt;li&gt;부모 테이블의 기본 키를 받아서 자식 테이블의 기본 키 + 외래 키로 사용하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비식별관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;받아온 식별자는 외래 키로만 사용&lt;/li&gt;
&lt;li&gt;새로운 식별자 추가&lt;/li&gt;
&lt;li&gt;단순히 외래 키로만 사용하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비식별 관계를 추천함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/15</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-11#entry15comment</comments>
      <pubDate>Sun, 17 Nov 2024 23:29:44 +0900</pubDate>
    </item>
    <item>
      <title>[PyCon] PyCon 2024 후기</title>
      <link>https://jineey-dev.tistory.com/entry/PyCon-PyCon-2024-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-4106323018420910&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9adM/btsKK0om74K/xKLTePgiAwzvrZ1L3JosNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9adM/btsKK0om74K/xKLTePgiAwzvrZ1L3JosNk/img.png&quot; data-alt=&quot;파이콘 10주년 기념&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9adM/btsKK0om74K/xKLTePgiAwzvrZ1L3JosNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9adM%2FbtsKK0om74K%2FxKLTePgiAwzvrZ1L3JosNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;292&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파이콘 10주년 기념&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소개&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;파이콘(PyCon)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://2024.pycon.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://2024.pycon.kr/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731834612844&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;파이콘 한국 2024&quot; data-og-description=&quot;&quot; data-og-host=&quot;2024.pycon.kr&quot; data-og-source-url=&quot;https://2024.pycon.kr/&quot; data-og-url=&quot;https://2024.pycon.kr/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://2024.pycon.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://2024.pycon.kr/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;파이콘 한국 2024&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;2024.pycon.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;날짜: 2024년 10월 26일 - 27일&lt;/li&gt;
&lt;li&gt;장소: 수원 컨벤션센터 3층&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;iframe mapdata=&quot;addr=%EA%B2%BD%EA%B8%B0%20%EC%88%98%EC%9B%90%EC%8B%9C%20%EC%98%81%ED%86%B5%EA%B5%AC%20%ED%95%98%EB%8F%99%20855-2&amp;amp;addtype=1&amp;amp;confirmid=1946823368&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A513190%2C%22mapCenterY%22%3A1051833%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A513194%2C%22y%22%3A1051839%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%88%98%EC%9B%90%EC%BB%A8%EB%B2%A4%EC%85%98%EC%84%BC%ED%84%B0%22%2C%22confirmid%22%3A1946823368%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=513190&amp;amp;mapY=1051833&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=4111761000&amp;amp;tel=031-303-6000&amp;amp;title=%EC%88%98%EC%9B%90%EC%BB%A8%EB%B2%A4%EC%85%98%EC%84%BC%ED%84%B0&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1731834702272&quot; id=&quot;maps_1731834702272&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EA%B2%BD%EA%B8%B0%20%EC%88%98%EC%9B%90%EC%8B%9C%20%EC%98%81%ED%86%B5%EA%B5%AC%20%ED%95%98%EB%8F%99%20855-2&amp;amp;addtype=1&amp;amp;confirmid=1946823368&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A513190%2C%22mapCenterY%22%3A1051833%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A513194%2C%22y%22%3A1051839%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%88%98%EC%9B%90%EC%BB%A8%EB%B2%A4%EC%85%98%EC%84%BC%ED%84%B0%22%2C%22confirmid%22%3A1946823368%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=513190&amp;amp;mapY=1051833&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=4111761000&amp;amp;tel=031-303-6000&amp;amp;title=%EC%88%98%EC%9B%90%EC%BB%A8%EB%B2%A4%EC%85%98%EC%84%BC%ED%84%B0&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=513190%2C1051833&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A513194%2C1051839&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세션 시간표&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 004.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bonT6t/btsKLfFzUt9/Vhwjnm0dV8uyTJIttUYDQk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bonT6t/btsKLfFzUt9/Vhwjnm0dV8uyTJIttUYDQk/img.jpg&quot; data-alt=&quot;1일차&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bonT6t/btsKLfFzUt9/Vhwjnm0dV8uyTJIttUYDQk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbonT6t%2FbtsKLfFzUt9%2FVhwjnm0dV8uyTJIttUYDQk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 004.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1일차&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 003.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRIkKW/btsKM2rbY90/ALK7CM1r0M0YUNBHwzXoy0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRIkKW/btsKM2rbY90/ALK7CM1r0M0YUNBHwzXoy0/img.jpg&quot; data-alt=&quot;2일차&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRIkKW/btsKM2rbY90/ALK7CM1r0M0YUNBHwzXoy0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRIkKW%2FbtsKM2rbY90%2FALK7CM1r0M0YUNBHwzXoy0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 003.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2일차&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 001.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z8HxS/btsKLvVIY20/VejKwPJYaKRMYVpPQNDWrK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z8HxS/btsKLvVIY20/VejKwPJYaKRMYVpPQNDWrK/img.jpg&quot; data-alt=&quot;인증샷1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z8HxS/btsKLvVIY20/VejKwPJYaKRMYVpPQNDWrK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz8HxS%2FbtsKLvVIY20%2FVejKwPJYaKRMYVpPQNDWrK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-04 001.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인증샷1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-05 005.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TTS40/btsKM5VMgtS/dJ1MKVJjJavtLiYxg7VTk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TTS40/btsKM5VMgtS/dJ1MKVJjJavtLiYxg7VTk1/img.jpg&quot; data-alt=&quot;인증샷2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TTS40/btsKM5VMgtS/dJ1MKVJjJavtLiYxg7VTk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTTS40%2FbtsKM5VMgtS%2FdJ1MKVJjJavtLiYxg7VTk1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_Photo_2024-11-17-18-08-05 005.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인증샷2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 날 수원 컨벤션센터에서는 펫축제가 열리고 있어서 많은 강아지들이 가득가득&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눈으로 귀여움을 잔뜩 담고 3층으로 이동하니, 접수처와 많은 후원사 부스들이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접수처에서는 이름표와 많은 굿즈들을 주었고 티켓 구매 했을 때 함께 구매한 티셔츠도 함께 수령할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 옆에서는 티셔츠, 후드집업 등 다양한 굿즈들을 추가 판매하고 있었는데 후드 집업이 너무 예뻐서 바로 구매!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_9999.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBzmhB/btsKL9Y8c4L/WdkHXwKuRK58OgCzJ4tue0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBzmhB/btsKL9Y8c4L/WdkHXwKuRK58OgCzJ4tue0/img.jpg&quot; data-alt=&quot;후드집업 인증샷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBzmhB/btsKL9Y8c4L/WdkHXwKuRK58OgCzJ4tue0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBzmhB%2FbtsKL9Y8c4L%2FWdkHXwKuRK58OgCzJ4tue0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-filename=&quot;IMG_9999.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;후드집업 인증샷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스, 크림, 두레이 등 다양한 후원사 부스에서 이벤트 참여하고 선물도 많이 받아왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 커뮤니티에서도 다양한 행사들을 홍보해서 나중에 참여해보려고 안내 책자들도 잔뜩 받아와서 두손 가득 짐을 들고 행사에 참여했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행사는 동일한 시간에 3개의 홀에서 각각 다른 세션을 발표하는 방식으로 진행됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리 공개된 세션 발표 주제를 보고, 본인이 흥미있고 궁금한 세션을 들으러 가면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 양일 모두 참석했고, 다음과 같은 세션에 참석하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주니어이자, 자바 개발자인 나는 모르는 내용이 가득했지만 모두가 눈이 반짝반짝한 채로 열정 가득히 발표를 하고 세션을 경청하는 모습에 덩달아 기분 좋은 자극이 되었고 파이썬이 어떠한 언어이고, 어떻게 쓰이는 지에 대해 조금이나마 이해할 수 있는 계기가 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1일차&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;⌜S⌟SDLC - Integrating AI for Proactive Security in Python Development&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;심의팅 / Noflag&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. The Power of code security &amp;amp; AI&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OWASP TOP 10 ISSUE&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. Insecure Coding in Python&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Unsafe programming - RCE, SQLI, Pickle module unsafely deserializes objects, unexpected behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. Leveraging AI for Vulnerability Detection&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Baking a generative AI Application&lt;/li&gt;
&lt;li&gt;About fine-tune&lt;/li&gt;
&lt;li&gt;Cloud Setting&lt;/li&gt;
&lt;li&gt;About RAG&lt;/li&gt;
&lt;li&gt;Choosing a method for training your model&lt;/li&gt;
&lt;li&gt;Safety filtering per request&lt;/li&gt;
&lt;li&gt;Local RAG with Gemma: 7B&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. Importance of SSDLC an Closing Remarks&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;when will the information security vuln be fixed?&lt;/li&gt;
&lt;li&gt;Risk level
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;High : Lower probability. Higher risk if it occurs&lt;/li&gt;
&lt;li&gt;Low: Low probability and low risk&lt;/li&gt;
&lt;li&gt;Critical: High probability and High risk of impact&lt;/li&gt;
&lt;li&gt;Medium: High probability but low risk&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Creating a secure program development cycle: gatekeeping at every step ..&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;FastAPI with Dependency Injector&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;한바름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 의존성 주입, 의존성 주입 프레임워크&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성 주입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소프트웨어 개발에서 중요한 디자인 패턴&lt;/li&gt;
&lt;li&gt;객체 지향 프로그램에서 객체 간의 의존성을 관리하는 방법&lt;/li&gt;
&lt;li&gt;객체는 자신이 필요한 의존성을 외부에서 주입 받을 수 있음&lt;/li&gt;
&lt;li&gt;코드의 재사용성이 높아지고, 테스트 가능성과 유지보수성이 크게 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;도우미 함수(helper function)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;def bbbb (aaaa: Callable = xxxx) -&amp;gt; &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파이썬은 함수도 객체이기 때문에, 클래스 외에도 함수에 의존성 주입도 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 함수로 다양한 세션 적용 가능&lt;/li&gt;
&lt;li&gt;재사용/관리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;의존성 주입 도입 결과
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성 객체가 어떻게 생성되는지 몰라도 됨&lt;/li&gt;
&lt;li&gt;의존성 객체 변경이 클라이언트 객체에 영향이 없음 (=결합도 낮아짐)&lt;/li&gt;
&lt;li&gt;의존성 객체의 라이프 사이클이 클라이언트 객체와 분리&lt;/li&gt;
&lt;li&gt;의존성이 변하는 케이스 대응
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 생성자 Args 변경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Engine() &amp;rarr; Engin(fule_type=&amp;rdquo;Gasoline&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클래스 타입의 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 의존성 주입 시 달라지는 점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성 외부에서 관리 (기존: 클라이언트 객체 생성만 하면, 의존성은 내부에서 생성)&lt;/li&gt;
&lt;li&gt;의존성 객체 라이프 사이클 관리 (기존: 클라이언트 객체 스코프에 의존성 객체 라이프사이클 종속)&lt;/li&gt;
&lt;li&gt;도우미 함수 필요 (선택)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 의존성 주입 프레임워크란?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성 주입 편의성 지원&lt;/li&gt;
&lt;li&gt;의존성 생성 관리(초기화 정보들, 의존성 생성타입)&lt;/li&gt;
&lt;li&gt;의존성 및 의존성이 주입된 객체 생성 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. FastAPI의 의존성 주입&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Depends()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성 생성 함수 등록&lt;/li&gt;
&lt;li&gt;의존성 필요 시 의존성 생성 함수 호출&lt;/li&gt;
&lt;li&gt;Caching 지원&lt;/li&gt;
&lt;li&gt;요청 처리 시 중복 로직 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FastAPI 종속&lt;/li&gt;
&lt;li&gt;Depends 사용한 의존성 주입만 교체 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dependency Injector
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상세한 문서&lt;/li&gt;
&lt;li&gt;의존성 주입 다양한 케이스 지원&lt;/li&gt;
&lt;li&gt;FastAPI 비종속&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;러닝커브 존재&lt;/li&gt;
&lt;li&gt;에러 지원 빈약&lt;/li&gt;
&lt;li&gt;FastAPI Depends() 완전한 대체는 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 적용후기 및 정리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이슈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전한 프레임워크는 아님&lt;/li&gt;
&lt;li&gt;컨테이너 사용하는 모듈간 순환 참조 가능성&lt;/li&gt;
&lt;li&gt;closure function 함수 주입은 안됨&lt;/li&gt;
&lt;li&gt;문서대로 해도 동작 안하는 경우도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;SpringBoot 하던 사람이 Django 찍먹 해 봄 : 저의 적응기를 공유합니다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;이지훈&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주요 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JAVA&lt;/li&gt;
&lt;li&gt;Spring/SpringBoot&lt;/li&gt;
&lt;li&gt;JPA&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;10년차&lt;/li&gt;
&lt;li&gt;JAVA 개발자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 계기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이직 &amp;rarr; 파이썬 주 언어 회사&lt;/li&gt;
&lt;li&gt;Flask 로 되어 있던 웹 프레임워크를 Django 전환할 필요성을 팀 내에서 합의&lt;/li&gt;
&lt;li&gt;팀 전체 러닝커브를 줄이기 위해 Django 튜토리얼 가이드의 작성 필요성&lt;/li&gt;
&lt;li&gt;Django 토이 프로젝트 시작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능: 질문 / 답변 / 회원가입 / 로그인(토큰 발급) / 추천(질문&amp;amp;답변)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 개발&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발 프로젝트 셋업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django 문서와 팀 동료 도움&lt;/li&gt;
&lt;li&gt;공식 문서의 &amp;lsquo;시작하기&amp;rsquo; 페이지 활용&lt;/li&gt;
&lt;li&gt;유저 가입 기능 &amp;rarr; Django Admin 기능 활용&lt;/li&gt;
&lt;li&gt;user 앱 추가 후 &lt;a href=&quot;http://setting.py&quot;&gt;setting.py&lt;/a&gt; 기본 사용자 모델 커스터마이징&lt;/li&gt;
&lt;li&gt;user 모델 추가, UserAdmin 모델 추가&lt;/li&gt;
&lt;li&gt;장고 기본 설정인 BasicTokenAuth를 그대로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SpringBoot 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring 공식 문서 참고&lt;/li&gt;
&lt;li&gt;SpringSecurity 선택&lt;/li&gt;
&lt;li&gt;라이브러리 Dependency SpringSecurity 업데이트&lt;/li&gt;
&lt;li&gt;SecurityConfing로 Security 설정 초기화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UserDetailService 초기화&lt;/li&gt;
&lt;li&gt;PasswordEncoder 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;순환참조 오류 발생&amp;hellip;..
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원인: configureGlobal 메서드와 filterChain 메서드에서 서로 PasswordEncoder를 참조하려고 하면서 순환 참조 오류 발생&lt;/li&gt;
&lt;li&gt;해결: Lombok&amp;nbsp;을 활용해 @ Lazy 를 사용하여 configureGlobal 메서드의 PasswordEncoder 에 작성 &amp;rarr; 지연 초기화 혹은 configureGlobal를 제거하고 USerDetailService를 상속받는 클래스를 직접 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;토큰 발급 API
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;view 단을 앱별로 모아서 관리하기 위해 API 앱 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관심사 분리&lt;/li&gt;
&lt;li&gt;유지보수성과 가독성 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;User 폴더 추가&lt;/li&gt;
&lt;li&gt;serializers 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직렬화, 역직렬화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;view에 function view 방식으로 ObtainTokenView 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그인 성공 시 토큰 발급, 로그아웃 시 토큰 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Serializer 와 view 에 대해 단위 테스트 코드 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SpringBoot 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring MVC 패턴에 따라 Controller/Service/Repository/DTO/Entity 계층별로 클래스 구성&lt;/li&gt;
&lt;li&gt;테스트 필수 계층 테스트 코드 작성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Controller&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;나머지 계층에도 테스트 코드가 필요하다면 해당 부분에 추가 작성&lt;/li&gt;
&lt;li&gt;하나의 API를 완성하기 위해 작성된 파일 총 10개, 총 라인 400줄, 글자수 1000자 이상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;URL 및 접근 권한 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 내의 &lt;a href=&quot;http://urls.py&quot;&gt;urls.py&lt;/a&gt; 파일만 찾아다니면 어떤 URL로 구성되어 있는 지 한눈에 파악 가능&lt;/li&gt;
&lt;li&gt;api 접근 권한은 api 별로 구현단에서 직접 지정할 수 있도록 함&lt;/li&gt;
&lt;li&gt;특정 리소스에 대한 일괄 접근 제한은 따로 구성해보지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SpringBoot 사용 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 Controller에 작성된 api에 URL 지정&lt;/li&gt;
&lt;li&gt;전체를 한눈에 파악하려면 외부 툴(swagger)이나 IDE의 도움 필요&lt;/li&gt;
&lt;li&gt;api별로 접근 제한 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@PreAuthorize(&amp;rdquo;hasRole(&amp;rsquo;ADMIN&amp;rsquo;)&amp;rdquo;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특정 리소스에 대한 일괄 접근 제한은 Security에서 구성 가능&lt;/li&gt;
&lt;li&gt;우선순위는 Security가 우선 적용됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. SUMMARY&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 셋업과 구조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 &lt;a href=&quot;http://urls.py&quot;&gt;urls.py&lt;/a&gt; 파일을 통해 URL을 중앙에서 관리&lt;/li&gt;
&lt;li&gt;접근 권한을 각 API에서 직접 제어 가능&lt;/li&gt;
&lt;li&gt;유지보수성과 가독성이 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SpringBoot
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 컨트롤러에서 URL 지정&lt;/li&gt;
&lt;li&gt;Security 설정에서 일괄 접근 제어 및 각각의 엔드포인트에서도 접근 제어 가능&lt;/li&gt;
&lt;li&gt;다양한 요구사항에 맞춘 세밀한 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;API 구현과 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 구조가 간결&lt;/li&gt;
&lt;li&gt;serializers와 view를 통해 효율적인 API 구현 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SpringBoot
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계층화된 구조로 인해 더 많은 파일과 코드 라인 필요 &amp;rarr; 유연성과 확장성 뛰어남&lt;/li&gt;
&lt;li&gt;테스트 코드 작성에서도 SpringBoot는 더 많은 계층에 대해 테스트 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Django의 DB Connection과 Transaction 관리&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;명세균&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;토스 백엔드 개발 6년차&lt;/li&gt;
&lt;li&gt;장고로 첫 개발 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. Django의 DB Connection 관리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;QuerySet 실행 과정&lt;/li&gt;
&lt;li&gt;Connections 이란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BaseConnectionHandler
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장고 DB Connection은 스레드/코루틴 task 단위로 DB_ALIAS별로 생성될 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ConnectionHandler
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BaseConnectionHandler 상속받음&lt;/li&gt;
&lt;li&gt;간단한 세팅함수와 현재 설정된 DB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. DB Connection 종료&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;request_started, request_finished 의 시그널에 close_old_connections 함수&lt;/li&gt;
&lt;li&gt;DatabaseWrapper 인스턴스에 할당된 close_at에 시간보다 현재시간이 크면 종료&lt;/li&gt;
&lt;li&gt;close_at 은 설정 가능 (CONN_MAX_AGE = 0: / = n: / = None: )&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. DB Connection 유의점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL server has gone away
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;wait_timeout 보다 더 긴 시간동안 커넥션 쿼리가 발생하지 않으면 커넥션 종료&lt;/li&gt;
&lt;li&gt;Django 서버가 그 사실을 모르고 종료된 커넥션에 쿼리를 호출하면 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해결방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CONN_MAX_AGE 는 DB 서버의 wait_timeout 보다 짧게 설정해야 DB 서버가 끊은 커넥션에 쿼리를 날리는 불상사 예방 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;예외
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CONN_MAX_AGE 값에 의해서 커넥션이 종료되는 시점은 request_started, request_finished 시점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;종종 만나는 커넥션 문제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청이 아닌 오래 걸리는 배치에서 쿼리가 나가는 상황&lt;/li&gt;
&lt;li&gt;요청이 아닌 오랫동안 실행되는 컨슈머, 워커에서 쿼리가 나가는 상황&lt;/li&gt;
&lt;li&gt;CONN_MAX_AGE보다 요청이 오래 걸리는 상황&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해결방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Health_check_enabled&lt;/li&gt;
&lt;li&gt;CONN_HEALTH_CHECKS &amp;rarr; 매번 ping을 날리게 되어 오버헤드 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장고의 CONN_MAX_AGE 개선
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;self.close_if_unusable_or_obsolete()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cursor를 반환할 때 CONN_HEALTH_CHECKS를 사용하지 않고 CONN_MAX_AGE가 더 잘 동작하도록 가능&lt;/li&gt;
&lt;li&gt;cursor 반환 전에self.close_if_unusable_or_obsolete()코드 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Aborted connection xxx to db
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;graceful하게 커넥션을 정리하고 서버가 내려가지 않음&lt;/li&gt;
&lt;li&gt;CONN_MAX_AGE를 wait_timeout 보다 짧게 설정하더라도 CONN_MAX_AGE가 지난 시점에 딱 커넥션을 종료해주지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. Transaction 관리 방법&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;using&lt;/li&gt;
&lt;li&gt;savepoint
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;default 값이 True이기 때문에, 기본적으로 트랜잭션 블록이 중첩되면 savepoint를 찍게 됨&lt;/li&gt;
&lt;li&gt;내부 트랜잭션에서 발생하는 에러를 제어하지 않으면 외부 트랜잭션까지 에러가 전파 되어서 전부 롤백이 되기 때문에 에러를 잘 핸들링하지 않으면 savepoint가 무의미해짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;attribute &amp;rarr; 현재 커넥션의 트랜잭션 상태 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. Transaction 이슈 경험 공유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;savepoint 이슈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL의 events_statements_summary_ &amp;hellip; 테이블&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;7. 결론&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CONN_MAX_AGE&lt;/li&gt;
&lt;li&gt;쓰레드/코루틴 task 단위&lt;/li&gt;
&lt;li&gt;savepoint&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;거의 모든 파이썬 이용자를 위한 거대언어모델(LLM)의 활용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;박상현(David)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. LLM이란?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Large Language Model
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Language
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자연어, 프로그래밍 언어, &amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Model
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;규칙 혹은 문법에 맞게 배열된 데이터들&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모델에 입력한 토큰들로 다음 토큰 예측
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아주 거대해서 성능이 좋은, 입력 토큰들의 다음 토큰을 예측하는 함수.&lt;/li&gt;
&lt;li&gt;파이썬의 &lt;b&gt;랭체인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. LLM과 대화하기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대화의 개념은 없음&lt;/li&gt;
&lt;li&gt;이전의 대화(prompt)를 넣어줘서 대화의 형식을 유도 &amp;rarr; prompt을 쌓아감.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 크기 관리 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이미 기존에 쌓인 메모리 활용?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 대화 이어가기&lt;/li&gt;
&lt;li&gt;RAG
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검색 &amp;rarr; DB &amp;rarr; 정보 &amp;rarr; context&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. LLM과 일하기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;할루시네이션(Hallucination) 문제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다음 토큰을 예측하여 글을 작성하는 능력만 있을 뿐, 정확하거나 올바른 데이터가 나오는 건 아님.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;String(알고 있는 문자열) &amp;rarr; LLM &amp;rarr; String &amp;rarr; 모르는 문자열 &amp;rarr; 문자열 처리 &amp;rarr; 원하는 문자열
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력값 외에 정확히 알거나 컨트롤 가능한 문자열이 없음.&lt;/li&gt;
&lt;li&gt;String(알고 있는 문자열)에 &lt;b&gt;알고 있는 문자열+알고 싶은 문자열 템플릿 제공&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역할 암시: 너는 인공지능 챗봇이야.&lt;/li&gt;
&lt;li&gt;답변 구조: CoT (LLM이 던지는 작은 의문(생각을 곱씹는 과정)을 토대로 결과를 도출하도록 생성)&lt;/li&gt;
&lt;li&gt;도구이름, 도구 입력
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도구: 인간이 미리 짜놓은 함수 (= 파이썬 함수)&lt;/li&gt;
&lt;li&gt;현실에서 존재하는 실제 함수(지식)를 사용. (학습한 내용에서 벗어남)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LLM은 다음 토큰을 재귀적으로 호출&lt;/li&gt;
&lt;li&gt;해당 과정은 &lt;b&gt;랭체인의 Agent&lt;/b&gt;에 구현되어 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 랭체인(LangChain)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수의 이름, 입력값의 형태, docstring 등의 정보를 문자열로 반환&lt;/li&gt;
&lt;li&gt;LLM 응답의 JSON 형식 문자열을 파싱하는 파서 구성&lt;/li&gt;
&lt;li&gt;생성을 중단할 stop word 설정&lt;/li&gt;
&lt;li&gt;LLM이 사용할 도구 이름들 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수의 이름을 신중하고 상세하게 선정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Context를 담은 프롬프팅에 사용할 메모리 설정&lt;/li&gt;
&lt;li&gt;LangChain Hub
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 템플릿 참고 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2일차&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;자동화된 파이썬 웹 프레임워크 API Schema 제작기: The long way around&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;조규진&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레블업 주식회사&lt;/li&gt;
&lt;li&gt;백엔드 개발자&lt;/li&gt;
&lt;li&gt;RestAPI, DB 설계, 컨테이너 설계 등 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. API 문서 자동화: 도입 배경&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Backend.AI는 REST API 및 GraphQL API를 병행하여 사용&lt;/li&gt;
&lt;li&gt;그동안 Backend.AI의 API 문서는 구현을 담당한 사람이 별개의 문서 파일을 임의로 채워 넣음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;많은 부분을 놓침&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 그동안 문제가 되지 않았던 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서드파티 API 호출 수요 부재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 고객들은 Backend.AI의 퍼스트 파티 프론트엔드인 WebUI 사용&lt;/li&gt;
&lt;li&gt;고객이 직접 API를 이용하여 Backend.AI의 기능에 접근할 일이 없었음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;작은 개발팀의 규모
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 개발팀이 그동안의 API 히스토리를 이해하고 있었음&lt;/li&gt;
&lt;li&gt;타 부서에서 백엔드 개발자에게 물어보면 되는 정도로 충분했음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 새롭게 등장한 과제들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 연동 수요 증가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Backend.AI가 제공하는 API를 가공하여 새로운 형태의 제품을 만들고자 하는 고객 등장&lt;/li&gt;
&lt;li&gt;기존 고객의 API 수요 심화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모니터링, 빌링 연동 등등&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사람이 늘어나고 코드 베이스가 방대해지면서 기존의 소통 방식으로는 한계에 봉착&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 비대면 소통(비동기 소통)을 가능하게 만들기 위해 문서화가 필요하다는 결론이 나옴.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 요구사항&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 RESP API Route에 대해 OpenAPI 형식의 API Schema 출력
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존의 API Handler에 손대지 않고도 문서화 가능해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. FastAPI를 선택하지 않은 이유&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_9977.HEIC.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oVlFU/btsKMi9nt4S/a7AGo2qF5NvKkeDUURfDEK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oVlFU/btsKMi9nt4S/a7AGo2qF5NvKkeDUURfDEK/img.jpg&quot; data-alt=&quot;FastAPI를 선택하지 않은 이유&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oVlFU/btsKMi9nt4S/a7AGo2qF5NvKkeDUURfDEK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoVlFU%2FbtsKMi9nt4S%2Fa7AGo2qF5NvKkeDUURfDEK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;IMG_9977.HEIC.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FastAPI를 선택하지 않은 이유&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FastAPI를 사용하기에는 11만줄의 코드 베이스를 가지고 있음&lt;/li&gt;
&lt;li&gt;10년이 넘은 레거시 소스임.&lt;/li&gt;
&lt;li&gt;OpenAPI Spec
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REST API를 구조화하여 표현하기 위해 등장한 개념&lt;/li&gt;
&lt;li&gt;API의 메서드, 리소스, 인증방식 등의 다양한 스펙 정의 가능&lt;/li&gt;
&lt;li&gt;JSON Schema에 REST API에 득화된 독자 정의 추가하여 탄생&lt;/li&gt;
&lt;li&gt;3.1은 JSON Schema와 100% 호환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;7. 구현&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적분석
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분석
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://Backend.AI&quot;&gt;Backend.AI&lt;/a&gt; Magager의 API Handler 정의 코드는 형식이 정형화 되어 있음&lt;/li&gt;
&lt;li&gt;그러니 ast 모듈을 이용해서 정적분석 시도&lt;/li&gt;
&lt;li&gt;소스코드 예시: Tech Stack&lt;/li&gt;
&lt;li&gt;Python ast Module
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬의 빌트 인 라이브러리&lt;/li&gt;
&lt;li&gt;파이썬 코드를 Abstract Syntax Tree 형식으로 해석하거나, 반대로 구조화된 AST를 파이썬 코드로 변환하는 기능 제공&lt;/li&gt;
&lt;li&gt;짜여진 파이썬 코드를 정적 분석 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;실행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 API Handler가 담긴 소스 코드를 AST로 변환&lt;/li&gt;
&lt;li&gt;Tree Traversal을 위해 AST &amp;rarr; XML 로 재변환&lt;/li&gt;
&lt;li&gt;정형화된 XML Path를 따라 모든 Handler의 구조를 순회하여 함수명, Request body 형식 수집&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 구현체가 의존하는 외부 패키지 설치 필요 없음&lt;/li&gt;
&lt;li&gt;빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노가다에 가까운 경로 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유지보수 불가능&lt;/li&gt;
&lt;li&gt;상대적 경로 (XML Path)&lt;/li&gt;
&lt;li&gt;API Handler의 선언 형식이 바뀌면 대응이 어려움&lt;/li&gt;
&lt;li&gt;한없이 낮아지는 코드 가독성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;code base에 도배되게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동적 분석
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분석
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 API Handler들의 entrypoint&lt;/li&gt;
&lt;li&gt;aiohttp Application&amp;nbsp; 객체의 내용을 동적으로 분석&lt;/li&gt;
&lt;li&gt;aiohttp.web.Application
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;entrypoint
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 Handelr 들이 이 객체 안에서 정리됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;실행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;web.Application 객체의 router.routes() 메서드를 이용해 등록된 모든 Route Handler 를 순회
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수명 등의 정보 가져옴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;set_handler_atttr(wrapped, &amp;ldquo;request_schema&amp;rdquo;, checker)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사람의 언어로 쓰여진 Spec generator를 만들 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Backend.AI의 의존성 설치 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;aiohttp, aiodocker ..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trafaret 한계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OpenAPI 스펙으로의 자동 변환 미지원&lt;/li&gt;
&lt;li&gt;primitive type이 어떤 API 형식으로 정의되는 지를 모두 정의 필요&lt;/li&gt;
&lt;li&gt;응답 데이터에 대한 타입 정의를 추가 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pydantic 도입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Trafaret에 비해 Python typing 친화적&lt;/li&gt;
&lt;li&gt;추가적인 구현 없이도 Open Spec 변환 가능&lt;/li&gt;
&lt;li&gt;typnig.get_type_hints() 함수를 사용하여 파이썬 객체의 타입 힌트 정보를 동적으로 가져올 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;8. 결론&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보완필요한 점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 Response Code 정보를 알려줄 필요가 있음&lt;/li&gt;
&lt;li&gt;모든 API Hander를 Pydantic으로 변환 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;레거시가 많지 않다면 FastAPI 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Python ASGI 서버 구현기 with Pyo3&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;민태인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NavyTree CTO
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배우들 오디션 숏폼 제작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장고로 입문&lt;/li&gt;
&lt;li&gt;PyCon 2019년 ~&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 프로젝트 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grais-asgi
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rust Asyncronous Server Gateway Interface의 두문자 에너그램&lt;/li&gt;
&lt;li&gt;Python asyncio 생태계와 잘 호환되면서 높은 성능이 높음&lt;/li&gt;
&lt;li&gt;grais
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rust 기반의 ASGI 서버 구현체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Uvicorn, hypercorn과 동일한 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로젝트를 시작하게 된 계기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;짐 캘런
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;본질을 이해하는 사람들은 극소수다.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[low level] 드라이버 - 운영체제 - 네트워크 프로토콜 - ASGI - 애플리케이션 [high level]
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 프로토콜, ASGI에 지식이 부족함을 느낌&lt;/li&gt;
&lt;li&gt;부족함을 채우고자 프로젝트 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;한국에서 오픈소스가 나왔으면 좋겠다는 희망
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로 만들고, 써보고, 피드백을 요구하는 Pycon 강연들이 많아지길 바람.&lt;/li&gt;
&lt;li&gt;본인이 먼저 행동하게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 사전지식&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rust
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 프로그래밍이 주 목적&lt;/li&gt;
&lt;li&gt;타입 시스템으로 컴파일 시간에 메모리 안정성을 보장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수의 수명(lifetime) 추척&lt;/li&gt;
&lt;li&gt;예외 처리대신 에러 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;어려운 난이도&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;바인딩
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍 언어가 해당 언어에 네이티브하지 않는 외부 라이브러리나 운영 체제 서비스를 사용할 수 있도록 만들어주는 글루 코드를 제공하는 API&lt;/li&gt;
&lt;li&gt;Pyo3
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 많이 쓰이는 Python-Rust 바인딩&lt;/li&gt;
&lt;li&gt;Pydantic 등에 사용 많이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 시행착오&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[구현기1] asyncio.Protocol를 Rust로
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;속도를 최대로 하기 위함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무수한 lifetime 에러로 컴파일되지 않음&lt;/li&gt;
&lt;li&gt;Python 호출 코드가 많아짐&lt;/li&gt;
&lt;li&gt;Python으로 일부를 옮기고자 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[구현기2] HTTP 프로토콜과 asyncio.Porotcol 구현 분리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rust는 HTTP 프로토콜에만 집중&lt;/li&gt;
&lt;li&gt;데이터 송수신, 흐름 제어는 파이썬으로&lt;/li&gt;
&lt;li&gt;상태머신 기반&lt;/li&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lifetime 문제 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pyo3 한계상 코드가 살짝 난해하고 지저분함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[구현기3] 복잡한 단일 구현 나누기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;너무나 비대해진 Http11Connection&lt;/li&gt;
&lt;li&gt;ASGI &amp;nbsp;순서에 따라 단계 나눔&lt;/li&gt;
&lt;li&gt;scope 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[구현기4] 사용성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;핫 리로드, 앱 예외처리, graceful-shutdown &amp;hellip;&lt;/li&gt;
&lt;li&gt;편리함을 위한 CLI 인터페이스&lt;/li&gt;
&lt;li&gt;문서화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 느낀 점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접적으로 상관없는 애플리케이션을 개발할 때도 이해도가 올라간 느낌&lt;/li&gt;
&lt;li&gt;도전을 응원하고 발표하는 기회를 많이 가졌으면 함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 웹 프레임워크, DI&amp;nbsp;프레임워크 (개인적으로 추천!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. QnA&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. CTO 병행하면서 어떻게 구현을 했는지? 그리고 어느 시간에 주로 작업했는지?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 초기 시작 때엔 CTO가 아니었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 달~ 한달 반정도 작업, 주로 밤~새벽에 작업함, 3~4시간씩 작업함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Python Backend에 클라우드를 더하다&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;황정식 / Huston&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;백엔드 엔지니어&lt;/li&gt;
&lt;li&gt;장고 메인&lt;/li&gt;
&lt;li&gt;SecondSyndrome 회사에서 Kotlin 등 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. DRF 백엔드 개발의 장/단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장고와 함께 Django Integration을 지원하는 여러 라이브러리 활용&lt;/li&gt;
&lt;li&gt;빠른 웹 서비스 비즈니스 로직 개발 가능&lt;/li&gt;
&lt;li&gt;협업하기에 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠르게 개발을 할 순 있지만 성능에 대한 챌린지가 많음&lt;/li&gt;
&lt;li&gt;대량 트래픽 발생에 약한 모습을 보여줌
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Gunicorn - workers : 성능은 코어수 * 4개까지 가능&lt;/li&gt;
&lt;li&gt;GIL 등..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DRF Backend 개발의 단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 트랜잭션으로 보면 DRF도 크게 떨어지지 않음&lt;/li&gt;
&lt;li&gt;글로벌 기업에서도 Python을 활용하여 백엔드 개발 가능성을 봄.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 클라우드를 사용하여 단점 극복하려 함. (성능 개선, 가용성 높임, 파이썬의 장점 유지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 모빌리티 서비스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(차량 대여/반납 오버헤드 이슈와 해결)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초소형 전기차 대여 서비스&lt;/li&gt;
&lt;li&gt;앱: 회원/예약/대여/차량제어/반납&lt;/li&gt;
&lt;li&gt;On-Board-Diagnostics(차량 자가 진단 장치) - Provider Server(외부 서버) - OPEN/CLOSE&lt;/li&gt;
&lt;li&gt;서비스: 유저관리 / 차량관리 / 결제관리 / 대여관리 .. 등
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주로 DB에 데이터를 넣고 빼는 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이슈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;차량 관리/제어에서 성능 이슈가 생김 (메인 기능 ㅠㅠ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지1.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Tqrs/btsKLooRct4/G0fZpMTpJRiMtEeAtgefFk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Tqrs/btsKLooRct4/G0fZpMTpJRiMtEeAtgefFk/img.jpg&quot; data-alt=&quot;이미지1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Tqrs/btsKLooRct4/G0fZpMTpJRiMtEeAtgefFk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Tqrs%2FbtsKLooRct4%2FG0fZpMTpJRiMtEeAtgefFk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지1.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제사항
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 대기상태 (응답에 30s 소요)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지2.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7WpW6/btsKLg5Cmja/w1bk7tJiIcwK1QxbAZHwnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7WpW6/btsKLg5Cmja/w1bk7tJiIcwK1QxbAZHwnK/img.jpg&quot; data-alt=&quot;이미지2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7WpW6/btsKLg5Cmja/w1bk7tJiIcwK1QxbAZHwnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7WpW6%2FbtsKLg5Cmja%2Fw1bk7tJiIcwK1QxbAZHwnK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지2.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 응답 대기상태에서 신규 응답이 생기면 앱이 동작하지 않음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Celery &amp;amp; Beat
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불확실성을 AWS의 Lamda 사용하여 해결&lt;/li&gt;
&lt;li&gt;속도 개선
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lamda 사용 전(기존)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지3.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7n2oU/btsKLi9R2Nm/ctH893FtYeSSHlILRZBTpK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7n2oU/btsKLi9R2Nm/ctH893FtYeSSHlILRZBTpK/img.jpg&quot; data-alt=&quot;이미지3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7n2oU/btsKLi9R2Nm/ctH893FtYeSSHlILRZBTpK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7n2oU%2FbtsKLi9R2Nm%2FctH893FtYeSSHlILRZBTpK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지3.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lamda 사용 후&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지4.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBXe54/btsKMjtFOAw/zbEItdogUlsTGKryzKiULk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBXe54/btsKMjtFOAw/zbEItdogUlsTGKryzKiULk/img.jpg&quot; data-alt=&quot;이미지4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBXe54/btsKMjtFOAw/zbEItdogUlsTGKryzKiULk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBXe54%2FbtsKMjtFOAw%2FzbEItdogUlsTGKryzKiULk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지4.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 시간 단축 (약 8~9s)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지5.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRjGbl/btsKNb9ioU9/yV1XGDJsDacSMOq9jifGmK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRjGbl/btsKNb9ioU9/yV1XGDJsDacSMOq9jifGmK/img.jpg&quot; data-alt=&quot;이미지5&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRjGbl/btsKNb9ioU9/yV1XGDJsDacSMOq9jifGmK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRjGbl%2FbtsKNb9ioU9%2FyV1XGDJsDacSMOq9jifGmK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지5.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지5&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 파이썬 장점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불확실한 요소가 많지만 고민하는 시가능ㄹ 아껴 빠르게 구현 시작 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상각하는 대로
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬 백엔드에게 친숙한 파이썬 스크립트를 개발해서 창의력이 생김&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;문제 해결
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제를 쉽고 빠르게 해결할 수 있는 장점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 메시징 서비스 개발&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AS-IS 분석하여 TO-BE 요구사항 확인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요구사항
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지별 다른 서비스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Push: Firebase&lt;/li&gt;
&lt;li&gt;SMS: N사&lt;/li&gt;
&lt;li&gt;KAKAO: I사&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스케줄링 이슈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉시발송, 예약발송 필요&lt;/li&gt;
&lt;li&gt;고객별 메시지 내역 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이미 있는 코드 활용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;발송 스크립트를 활용하여 개발 기간 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결론
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 코드를 최대한 활용하여 스케줄링 기능 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 서비스로 모두 이관하여 개발 불가능&lt;/li&gt;
&lt;li&gt;서비스에서 제공하는 스케줄링 활용 불가능&lt;/li&gt;
&lt;li&gt;레거시 파이썬 스크립트는 최대한 수정없이 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개발 요구사항에 스케줄러도 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS에서 EventBridge 스케줄러 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;아키텍처 구성 전, PoC 작성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;One-time schedule&amp;nbsp;가능한 지, 얼마나 걸리는 지 검토&lt;/li&gt;
&lt;li&gt;가능성이 보여 진행하기로 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;아키텍처&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지6.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ESzh3/btsKMcVDPjF/Q83a6dCuVlka9Mw0wO9YU1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ESzh3/btsKMcVDPjF/Q83a6dCuVlka9Mw0wO9YU1/img.jpg&quot; data-alt=&quot;이미지6&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ESzh3/btsKMcVDPjF/Q83a6dCuVlka9Mw0wO9YU1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FESzh3%2FbtsKMcVDPjF%2FQ83a6dCuVlka9Mw0wO9YU1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-filename=&quot;이미지6.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지6&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. 결론&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬은 다음과 같은 자신의 성격과 잘 맞아서 좋음.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상상하는대로 재밌는 것을 구현하고 싶음&lt;/li&gt;
&lt;li&gt;빨리 구현해서 사용해보고 싶음&lt;/li&gt;
&lt;li&gt;어떤 새로운 걸 활용하고 싶음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파이썬과 클라우드를 활용하여 한계를 극복하는 경험 가졌으면 좋겠음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;오픈소스 프로젝트 - &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;코드 0줄부터 스타 1.3k까지&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;김동규&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AutoRAG CEO (Co-Founder)&lt;/li&gt;
&lt;li&gt;RAG 연구원&lt;/li&gt;
&lt;li&gt;디지털 노마드&lt;/li&gt;
&lt;li&gt;2번의 창업 경험 (이번이 3번째)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. AutoRAG란?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Star History 에서 참고 가능 (1월 오픈 ~ 현재 1.9k까지 성장함)&lt;/li&gt;
&lt;li&gt;RAG란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;Perplexity&lt;/span&gt; 에서 질의응답 시, 최신의 정보가 없어서 정확한 정보를 답변하지 못한 GPT와 달리 정확한 대답을 함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8; color: #333333; text-align: left;&quot;&gt;Perplexity&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt; : &lt;/span&gt;RAG 사용하여 ChatGPT와 동일한 기능을 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정확한 정보를 넣어주는 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LLM이 알았으면 하는 문서를 RAG에 넣어주면, 질문에 따라 알맞은 문서를 RAG가 찾아 LLM에 제공&lt;/li&gt;
&lt;li&gt;private하거나 domaintic한 정보를 LLM이 활용할 수 있도록 하는 기술&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;문서 더미에서 필요한 정보를 검색하여 LLM이 가지고 있던 정보를 전달함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RAG를 만들 때 큰 문제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터셋을 만들 때마다 달라짐.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 문서에 좋은 방법이 없음&lt;/li&gt;
&lt;li&gt;각 문서마다 성능이 드라마틱하게 다름&lt;/li&gt;
&lt;li&gt;각각 적합한 방법을 찾아서 적용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;적합한 방법론이 무궁무진하게 많음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;랭체인 혹은 라마인덱스에 구현되어 있는 것들은 빙산의 일각&lt;/li&gt;
&lt;li&gt;모든 것을 직접 구현하고 성능을 측정해서 최적화하기엔 너무나 많은 시간 소요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;AutoRAG&lt;/span&gt;이란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RAG 자동 최적화 툴&lt;/li&gt;
&lt;li&gt;수많은 RAG 실험을 효율적으로 편하게 하도록 자동화&lt;/li&gt;
&lt;li&gt;YAML 설정파일만으로 여러 RAG 모듈을 자동 최적화&lt;/li&gt;
&lt;li&gt;문서로부터 평가 데이터셋 자동 생성&lt;/li&gt;
&lt;li&gt;직접 구현하지 않아도 최적의 RAG 조합을 찾음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 어떻게 오픈소스 프로젝트를 성장시켰는가?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈소스 홍보 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커뮤니티 등에 홍보
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한달동안의 최소한의 기능 구현 후 런칭&lt;/li&gt;
&lt;li&gt;긱뉴스, 레딧, 아카라이브, 해커뉴스 등
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;긱뉴스, 레딧에서 좋은 반응 &amp;rarr; 200개 정도의 스타를 받음.&lt;/li&gt;
&lt;li&gt;기대했던 해커뉴스에는 좋은 반응을 얻지 못함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;링크드인 활동 시작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;링크드인으로 관련 업계 사람들에게 쉽게 도달 가능&lt;/li&gt;
&lt;li&gt;최초에는 짧은 글을 올림 (단순 홍보)&lt;/li&gt;
&lt;li&gt;요즘에는 개발 블로그를 작성 후, 해당 블로그의 짧은 요약과 함께 공유&lt;/li&gt;
&lt;li&gt;라마인덱스 CEO에게 DM 및 일촌 신청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라마인덱스를 사용하여 개발중임을 Git Link와 함께 DM을 보냄&lt;/li&gt;
&lt;li&gt;라마인덱스 SNS에 AutoRAG가 홍보된 것이 결정적인 계기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최근에 또 다른 관계자에게 홍보가 되어 1.7k &amp;rarr; 1.9k 로 성장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;직접 발표하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Open-Source Gen AI Tools Demo Day에서 발표 &amp;rarr; 스타 900개&lt;/li&gt;
&lt;li&gt;AI 전문 유튜버 테디노트님의 라이브 참여
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한국 RAG 커뮤니티에서 알려지게 됨&lt;/li&gt;
&lt;li&gt;스타 1k 달성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이후 링크드인, 컨퍼런스, 개발 블로그 꾸준히 하고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;홍보에는 왕도가 없음을 알게 됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일회성이 아닌 꾸준히 유입될 수 있는 컨텐츠를 늘리는 것이 중요&lt;/li&gt;
&lt;li&gt;자신의 속도에 맞춰서 천천히 하지만 꾸준히 홍보 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 오픈소스를 하면서 힘들 때&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복되는 문서화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈소스는 문서화가 생명
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불특정 다수가 보는 문서&lt;/li&gt;
&lt;li&gt;문서가 없으면 오픈소스를 활용 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사용자 파악이 어려움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;누가 얼마나 쓰는지 파악이 어려움&lt;/li&gt;
&lt;li&gt;깃허브 스타가 곧 사용을 의미하지 않음&lt;/li&gt;
&lt;li&gt;Contribute나 디스코드 질문 등만으로 사용자 파악 가능&lt;/li&gt;
&lt;li&gt;전체 사용자 중에 일부만 볼 수 있는 기분 때문에 허무할 때가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반복되는 질문에 지침
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FAQ 등을 만들어두어도 반복되는 질문들이 있음&lt;/li&gt;
&lt;li&gt;문서화 및 코드 로직 수정 등으로 고치려고 노력중&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수익화 되지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재는 사업화 진행중(일부 기능 유료화)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 오픈소스를 하는 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자는 &amp;lsquo;오픈소스&amp;rsquo;를 좋아하기 때문
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈소스 홍보는 &amp;lsquo;홍보가&amp;rsquo; 아닌 &amp;lsquo;정보 공유&amp;rsquo; 같이 받아들여지기 때문&lt;/li&gt;
&lt;li&gt;부담없이 프로젝트 정보가 퍼질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 기여
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 Full-time 개발팀 인원은 3명&lt;/li&gt;
&lt;li&gt;이슈와 생각하지 못한 버그에 대응 가능&lt;/li&gt;
&lt;li&gt;오픈소스이기에 버그를 리포트 받을 수 있음&lt;/li&gt;
&lt;li&gt;외부PR을 적극적으로 수용 가능&lt;/li&gt;
&lt;li&gt;사례
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;후쿠오카 개발자가 Full-Request 요청&lt;/li&gt;
&lt;li&gt;모든 프롬프트를 일본어로 번역&lt;/li&gt;
&lt;li&gt;2개국어(영어, 한국어) 지원 &amp;rarr; 3개국어(영어, 한국어, 일본어) 지원으로 확대&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시작하기 쉬움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오픈소스의 퀄리티 요구는 생각보다 낮아 최소 기능으로 검증 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검증: 깃허브 레포 만드는 것.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최초에 12개의 모듈 &amp;rarr; 현재 50개의 기능으로 확대함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. 정리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 분야의 오픈소스가 활성화되었으면 좋겠음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;해커의 관점에서 바라본 Django Framework&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;윤석찬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경희대 컴공과&lt;/li&gt;
&lt;li&gt;Python / Django Security Contributor&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. Django가 제공하는 기본적인 보안 기능&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XXS Protection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cross-Site-Scripting 웹사이트에 악성 스크립트를 삽입하는 공격 방법&lt;/li&gt;
&lt;li&gt;주로 HTML, JS 같은 언어를 이용해 악성 스크립트 삽입&lt;/li&gt;
&lt;li&gt;사용자로 하여금 의도하지 않은 행위를 하게 만드는 위험 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL Injection Protection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 쿼리에 악성 SQL 코드를 삽입하여 데이터를 조작하거나 탈취하는 공격 방법&lt;/li&gt;
&lt;li&gt;Django ORM 기능으로 SQL Injection 보호&lt;/li&gt;
&lt;li&gt;버전에 따라 지원 안될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CSRF Protection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSRF: 사용자가 자신의 의지와는 무관하게 악의적인 요청을 보내도록 만드는 웹 보안 취약점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Clickjacking Protection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;X-Frame-Options에 &amp;lsquo;DENY&amp;rsquo; 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Password Cracking Protecction
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디폴트로 &amp;lsquo;PBKDF2Passworldhasher&amp;rsquo; 사용&lt;/li&gt;
&lt;li&gt;SHA256 알고리즘을 720,000번 반복 &amp;rarr; 해커들이 쉽게 크랙하지 못하도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 발견된 취약점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1-Day Vulnerabilities
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1-day: 취약점에 대한 정보가 공개되고, 패치 버전이 존재하는 취약점&lt;/li&gt;
&lt;li&gt;취약점 목록
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력받은 값을 검증받지 않고 쿼리에 바로 넣고 실행이 되어 악의적인 쿼리 호출 가능&lt;/li&gt;
&lt;li&gt;복잡한 정규식 사용, 입력길이 제한 없음, 반복적인 패턴 &amp;rarr; 과도한 CPU 사용으로 DoS 유발 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강연자가 발견한 취약점!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Conclusion
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최근 공개된 보안 이슈는 발생 가능성낮음&lt;/li&gt;
&lt;li&gt;SQL Injection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잘 사용되지 않는 기능을 사용해 트리거 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DoS
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비정상적으로 큰 입력값이 있어야 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;결론
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django는 여전히 안전하다고 확신함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 개발 시 주의해야할 점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XXS
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 시, HttpResponse()를 사용하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장고의 템플릿 필터를 사용하지 않기 때문임.&lt;/li&gt;
&lt;li&gt;사용자가 입력한 값이 코드에 삽입됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;템블릿 필터 &amp;lsquo;safe&amp;rsquo;를 사용하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 안전하다고 가정하고 진행하기 때문에 악의적인 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;템블릿 필터에서 &amp;lsquo;autoescape off&amp;rsquo; 사용&lt;/li&gt;
&lt;li&gt;URL 형식 검증이 없는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;허용된 프로토콜만 사용 가능하도록 제한 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL Injection
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Raw SQL 이용 시 안전하지 않은 방법으로 사용자 입력이 포함되는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;String Concatenation, Format String, &amp;hellip;&lt;/li&gt;
&lt;li&gt;Order by 구문 사용 시 주의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장고를 2022년 이후 업데이트를 하지 않은 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Third Party Library
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Exploitable Third-party Modules
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django-rest-framework, etc &amp;hellip;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강연자가 Django-rest-framework 에서 중급 정도의 취약점 발견&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정기적으로 라이브러리 업데이트 필요&lt;/li&gt;
&lt;li&gt;보안 문서 및 코드 리뷰 확인 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Regular Expression Denial of Service
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;백트래킹을 많이 유발하는 복잡한 정규표현식 패턴 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SSRF
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공격자가 의도하지 않은 대상에 서버 측 요청을 할 수 있도록 허용하는 취약점&lt;/li&gt;
&lt;li&gt;내부 리소스에 대한 무단 액세스로 이어짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버를 프록시처럼 사용하여 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;엄격한 방화벽 규칙 사용 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SECRET_KEY Leakage
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 노출 시 문제가 생김
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세션 하이재킹&lt;/li&gt;
&lt;li&gt;CSRF 토큰 위조&lt;/li&gt;
&lt;li&gt;암호화된 데이터 복호화&lt;/li&gt;
&lt;li&gt;서명된 데이터 위조&lt;/li&gt;
&lt;li&gt;애플리케이션 전체 장악&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;실제 발생한 보안 문제 발생한 사례가 많음&lt;/li&gt;
&lt;li&gt;PicklesSerializer와 결합하여 더 큰 문제 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 결론&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Django는 안전해지고 있다&lt;/li&gt;
&lt;li&gt;그럼에도 만능이 아니기 때문에 보안성 유의 필요&lt;/li&gt;
&lt;li&gt;꾸준한 업데이트 필수적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. QnA&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. 웹개발 시 보안에 관심이 많은데, 소개해주신 패턴 말고도 최근에 있었던 이슈나 놓치기 좋은 포인트 소개 부탁&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 최근에 프레임워크가 고도화되고 보안 취약점이 사라지고 있어서 DoS 취약점에 관심을 가지고 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 비해 Http 파싱 등과 같이 보안 취약점이 발생하는 경우가 많음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 업데이트를 하는 것이 가장 중요하고 좋은 예방책임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. 취약점 발견은 테스트와 코드 분석 중 어떤 방법으로 발견?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 코드를 통해 발견함. 코드를 한두달씩 봄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. 코드를 어떤 방법으로 보는지? (위에서부터 차례로? 아니면 한 모듈을 잡고 보는지?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 취약점이 많이 발생하는 유형이 있기 때문에, 관련 코어부터 점검함&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;험난한 암호화폐 세상을 여행하려는 Python 유저들을 위한 안내서&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; ️&amp;nbsp;이왕원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 소개&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AI 스타트업 코디미에서 CTO&lt;/li&gt;
&lt;li&gt;AI, Web, Blockchain 등 공부 중&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 암호화폐 생태계 순환 원리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검증자, 빌더(개발자 등), 유저&lt;/li&gt;
&lt;li&gt;검증자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블록체인 노드 유지&lt;/li&gt;
&lt;li&gt;물리적인 인프라에 기여&lt;/li&gt;
&lt;li&gt;해당 체인의 가상화폐를 얻음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;빌더
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DApp 개발&lt;/li&gt;
&lt;li&gt;프로젝트 개발 및 운영에 기여&lt;/li&gt;
&lt;li&gt;DApp 사용 수수료, 추가화폐 발행 등 다양한 수익모델을 얻음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사용자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DApp 및 생태계 이용&lt;/li&gt;
&lt;li&gt;가상화폐 사용을 기여함&lt;/li&gt;
&lt;li&gt;DApp 및 생태계 이용을 얻음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서로 상호보완적인 역할이기 때문에 생태계 유지 및 성장 가능&lt;/li&gt;
&lt;li&gt;역설적으로는, 이 생태계가 완성되기 전까지는 이 선순환구조가 성립될 수 없다는 치명적인 문제가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 암호화폐 에어드랍&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에어드랍(Airdrop)?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생태계에 기여한 실유저/빌더에게 암호화폐를 주는 정책&lt;/li&gt;
&lt;li&gt;재단 측에서는 초기 생태계 구성원을 끌어들이기 위해 암호화폐 에어드랍을 적극적으로 시행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에어드랍 헌터
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에어드랍 작업만 전문적으로 함&lt;/li&gt;
&lt;li&gt;생태계에 장기적으로 좋지 않은 영향을 줌&lt;/li&gt;
&lt;li&gt;결국 프로젝트 측에서는 이를 악성 시빌(sybil) 공격으로 규정하기에 이름
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 개인이 다수의 계정이나 노드, 컴퓨터를 구성해 네트워크를 공격하는 기법 중 하나&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 현상금 사냥꾼&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LayerZero
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 체인의 자산을 통합하는 크로스체인 플랫폼&lt;/li&gt;
&lt;li&gt;초기부터 꾸준하게 사용한 유저들에게 에어드랍 약속&lt;/li&gt;
&lt;li&gt;시간이 흘러 자체 코인을 발행하는 시점에서 총 지갑 수가 250만 개에 육박&lt;/li&gt;
&lt;li&gt;현상금 사냥꾼 제도 출범
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시빌공격하는 사람을 잡으면 15% 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;대부분 여러 개의 계정을 가지고 있는 게 디폴트였기 때문에 문제가 됨&lt;/li&gt;
&lt;li&gt;서로 제보하고 신상캐고 공개저격하는 문제가 생김&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. 파이썬을 활용한 온체인 데이터 분석/수집&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현상금 사냥꾼 &amp;mdash;&amp;gt; 데이터 분석과 동일함&lt;/li&gt;
&lt;li&gt;각 트랜잭션 해시값을 비롯한 분석에 필요한 데이터 제공 (.csv)&lt;/li&gt;
&lt;li&gt;table 데이터이기 때문에 파이썬 데이터분석 유저가 다루기 좋은 형태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;범용적인 데이터 분석 툴(numpy, pandas 등) 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;아이디어 예시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실유저는 장기 이용, Sybiler들은 단기 사용했을 것이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;월 별로 평균 등 디테일한 분석 필요&lt;/li&gt;
&lt;li&gt;Seaborn으로 사용기간 히스토그램 시각화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sybil 지갑이라면 에어드랍 스냅샷 이후에 자금을 전부 회수했을 것이고, 실사용 지갑이면 계속 쓸테니 돈이 들어있지 않을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명확하게 판별하는 기준을 이야기할 수 있으면, 어떤 수단과 방법을 동원해도 괜찮음&lt;/li&gt;
&lt;li&gt;주어진 데이터로만 분석하지 않아도 됨&lt;/li&gt;
&lt;li&gt;주어진 데이터에는 지갑 잔액 정보가 없기 때문에 web3.py로 직접 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이더리움 호환 블록체인과 상호작용할 수 있게 해주는 파이썬 모듈&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sybil 지갑이라면 에어드랍 스냅샷 이후에는 지갑을 사용하지 않았을 것이고, 실사용지갑이면 계속 쓸테니 트랜잭션이 계쏙 발생했을 것이다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 지갑별 트랜잭션 데이터를 집계&lt;/li&gt;
&lt;li&gt;block explorer 사용하여 분석&lt;/li&gt;
&lt;li&gt;requests와 같은 모듈을 사용하여 RestAPI로 직접 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. 정리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;24.06.15 기준, 공식 발표에 대한 Sybil 기준은 아래와 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브릿지 금액이 1달러 미만&lt;/li&gt;
&lt;li&gt;대량의 지갑 사이에 일정한 트랜잭션(tx) 기록이 있는지&lt;/li&gt;
&lt;li&gt;서비스 오픈 12달 이내 3번 미만의 트랜잭션 유무&lt;/li&gt;
&lt;li&gt;스냅샷 이후의 트랜잭션 기록이 없는지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;확실한 기준을 정립하기 어려움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 조건이 겹쳤을 때 판별하는 것으로 보완&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 과정이 유의미한 이유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타 도메인의 데이터분석과 크게 다르지 않음&lt;/li&gt;
&lt;li&gt;난이도가 높지 않음&lt;/li&gt;
&lt;li&gt;가설 및 접근 전략을 세우기 위해 도메인 지식 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Doing/Conference</category>
      <category>pycon</category>
      <category>pycon2024</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <category>파이콘</category>
      <category>파이콘2024</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/14</guid>
      <comments>https://jineey-dev.tistory.com/entry/PyCon-PyCon-2024-%ED%9B%84%EA%B8%B0#entry14comment</comments>
      <pubDate>Sun, 17 Nov 2024 18:59:13 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #10</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-10</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.1 단방향 연관관계 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.2 연관관계 사용 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.3 양방향 연관관계 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.4 연관관계의 주인 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.5 양방향 연관관계 저장 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.6 양방향 연관관계의 주의점 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5.7 정리 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;  개요&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뱡향(Direction)&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향: 관계에서 둘 중 한 쪽만 참조하는 것&lt;/li&gt;
&lt;li&gt;양방향: 양쪽 모두 서로 참조하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다중성(Multiplicity)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연관관계의 주인(Owner)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  단방향 연관관계&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다대일(N:1) 단방향 관계 이해가 가장 우선시 되어야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 회원과 팀이 있고, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;회원은 하나의 팀에만 소속&lt;/span&gt;될 수 있을 때 회원과 팀은 다대일 관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 연관관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 객체는 Member.team 필드(멤버변수)로 팀 객체와 연관관계를 맺음&amp;nbsp;&lt;/li&gt;
&lt;li&gt;회원 객체와 팀 객체는 &lt;b&gt;단방향 관계&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;회원은 Member.team 필드를 통해서 팀을 알 수 있지만 반대로 팀은 회원을 알 수 없음&lt;br /&gt;(방법: &lt;span style=&quot;background-color: #dddddd;&quot;&gt;member.getTeam()&lt;/span&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;테이블 연관관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺음&amp;nbsp;&lt;/li&gt;
&lt;li&gt;회원 테이블과 팀 테이블은 &lt;b&gt;양방향 관계&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;회원 테이블의 TEAM_ID 외래 키를 통해서 회원과 팀을 조인 할 수 있고, 반대로 팀과 회원도 조인할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체 연관관계 vs 테이블 연관관계 차이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조를 통한 연관관계는 언제나 단방향&lt;/li&gt;
&lt;li&gt;객체간에 연관관계를 양방향으로 하기 위해서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;반대쪽에도 필드를 추가하여 참조를 보관&lt;/span&gt;해야 함&lt;br /&gt;(➡️ 이는 정확히 말하면 양방향 관계가 아닌 &lt;b&gt;서로 다른 단방향 관계 2개&lt;/b&gt;임)&lt;/li&gt;
&lt;li&gt;객체는 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;참조(주소)&lt;/span&gt;&lt;/b&gt;로 연관관계를 맺고, 테이블은 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;외래 키&lt;/span&gt;&lt;/b&gt;로 연관관계를 맺음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &amp;nbsp; 순수한 객체 연관관계 방법&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1731672512201&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Member {
    private String id;
    private String username;
    
    private Team team; //팀의 참조를 보관
    
    public void setTeam(Team team){
    	this.team = team;
    }
    
}

public class Team {
    private String id;
    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &amp;nbsp; 테이블 연관관계&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1731672704642&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE MEMBER (
    MEMBER_ID VARCHAR(225) NOT NULL,
    TEAM_ID VARCHAR(225),
    USERNAME VARCHAR(225),
    PRIMARY KEY (MEMBER_ID)
}

CREATE TABLE TEAM (
    TEAM_ID VARCHAR(225) NOT NULL,
    NAME VARCHAR(225),
    PRIMARY KEY (TEAM_ID)
}

ALTER TABLE MEMBER ADD CONSTRAINT FK_MEMBER_TEAM
     FOREIGN KEY (TEAM_ID) REFERENCE TEAM&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &amp;nbsp; 객체관계 매핑&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1731672874787&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id
    @Column(name=&quot;MEMBER_ID&quot;)
    private String id;
    
    //연관관계 매핑
    @ManyToOne
    @JoinColumn(name=&quot;TEAM_ID&quot;)
    private Team team;
    
    //연관관계 설정
    public void setTeam(Team team){
    	this.team = team;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;✅ &lt;b&gt;@ManyToOne&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다대일 관계에서 사용하는 어노테이션&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 112px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.031%; height: 20px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 52.1704%; height: 20px;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.7985%; height: 20px;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.031%; height: 20px;&quot;&gt;optional&lt;/td&gt;
&lt;td style=&quot;width: 52.1704%; height: 20px;&quot;&gt;false로 설정하면 연관된 엔티티가 항상 있어야 함&lt;/td&gt;
&lt;td style=&quot;width: 28.7985%; height: 20px;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 36px;&quot;&gt;
&lt;td style=&quot;width: 19.031%; height: 36px;&quot;&gt;fetch&lt;/td&gt;
&lt;td style=&quot;width: 52.1704%; height: 36px;&quot;&gt;글로벌 페치 전략 설정&lt;/td&gt;
&lt;td style=&quot;width: 28.7985%; height: 36px;&quot;&gt;@ManyToOne=FetchType.EAGER&lt;br /&gt;@OneToMany=FetchType.LAZY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 19.031%; height: 18px;&quot;&gt;cascade&lt;/td&gt;
&lt;td style=&quot;width: 52.1704%; height: 18px;&quot;&gt;영속성 전이 기능 사용&lt;/td&gt;
&lt;td style=&quot;width: 28.7985%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 19.031%; height: 18px;&quot;&gt;targetEntity&lt;/td&gt;
&lt;td style=&quot;width: 52.1704%; height: 18px;&quot;&gt;연관된 엔티티의 타입 정보 설정&lt;br /&gt;이 기능은 거의 사용하지 않음&lt;br /&gt;컬렉션을 사용해도 제네릭으로 타입 정보를 알 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 28.7985%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;@JoinColumn&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;외래 키를 매핑할 때 사용하는 어노테이션&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;생략 시 외래 키를 찾을 때 기본값 사용함 ➡️ 필드명(team) + 언더바( _ ) + 참조하는 테이블의 컬럼명(TEAM_ID) = team_TEAM_ID&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 175px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.3566%; height: 20px;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.31%; height: 20px;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;width: 26.3566%; height: 19px;&quot;&gt;매핑할 외래 키 이름&lt;/td&gt;
&lt;td style=&quot;width: 40.31%; height: 19px;&quot;&gt;필드명+ 언더바(_) + 참조하는 테이블의 기본 키 컬럼명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;referencedColumnName&lt;/td&gt;
&lt;td style=&quot;width: 26.3566%; height: 18px;&quot;&gt;외래키가 참조하는 대상 테이블의 컬럼명&lt;/td&gt;
&lt;td style=&quot;width: 40.31%; height: 18px;&quot;&gt;참조하는 테이블의 기본 키 컬럼명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 10px;&quot;&gt;foreignKey(DDL)&lt;/td&gt;
&lt;td style=&quot;height: 10px; width: 26.3566%;&quot;&gt;외래 키 제약조건을 직접 지정 가능&lt;br /&gt;테이블을 생성할 때만 사용됨&lt;/td&gt;
&lt;td style=&quot;width: 40.31%; height: 10px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 108px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 108px;&quot;&gt;unique&lt;br /&gt;nullable&lt;br /&gt;insertable&lt;br /&gt;updatable&lt;br /&gt;columnDefinition&lt;br /&gt;table&lt;/td&gt;
&lt;td style=&quot;width: 66.6666%; height: 108px;&quot; colspan=&quot;2&quot;&gt;@Column 속성과 동일&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  연관관계 사용&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 저장&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731673461452&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void testSave() {

    //팀1 저장
    Team team1 = new Team(&quot;team1&quot;, &quot;팀1&quot;);
    em.persist(team1);
    
    //회원1 저장
    Member member1 = new Member(&quot;member1&quot;, &quot;회원1&quot;);
    member1.setTeam(team1); //회원 -&amp;gt; 팀 참조
    em.persist(member1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 조회&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 그래프 탐색&lt;/li&gt;
&lt;li&gt;객체지향 쿼리 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731673599570&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//객체 그래프 탐색
Member member = em.find(Member.class, &quot;member1&quot;);
Team team = memver.getTeam(); //객체 그래프 탐색
System.out.println(&quot;팀 이름 = &quot; + team.getName()); //출력결과: 팀 이름 = 팀1

//객체지향 쿼리 사용(JPQL)
private static void queryLogicJoin(EntityManager em){
    String jpql = &quot;select m from Member m join m.team t &quot;
    				+ &quot;where t.name=:teamName&quot;;
    
    List&amp;lt;Member&amp;gt; resultList = em.createQuery(jpql, Member.class)
                                .setParameter(&quot;teamName&quot;, &quot;팀1&quot;);
                                .getResultList();
                                
    for (Member member : resultList){
    	System.out.println(&quot;[query] member.username= &quot; + member.getUsername());
        //출력결과
        //[query] member.username= 회원1
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;:teamName
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&amp;nbsp;:&amp;nbsp;&lt;/span&gt; 로 시작하는 것은 파라미터를 바인딩 받는 문법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 수정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731674178646&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static void update (EntityManager em) {

    //새로운 팀2
    Team team2 = new Team(&quot;team2&quot;, &quot;팀2&quot;);
    em.persist(team2);
    
    //회원1에 새로운 팀2 설정
    Member member = em.find(Member.class, &quot;member1&quot;);
    member.setTeam(team2);
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 연관관계 제거&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731674275016&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static void delete (EntityManager em){
    Member member1 = em.find(Member.class, &quot;member1&quot;);
	member.setTeam(null); //연관관계 제거
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1731674312862&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE
	MEMBER
SET
	TEAM_ID = null
WHERE
	ID='member1'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 연관된 엔티티 삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 있던 연관관계를 먼저 제거 후 삭제 해야 함&lt;/p&gt;
&lt;pre id=&quot;code_1731674379657&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;member1.setTeam(null); //회원1 연관관계 제거
member2.setTeam(null); //회원2 연관관계 제거
em.remove(team); //팀 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  양방향 연관관계&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원-&amp;gt;팀: 다대일 관계, 팀-&amp;gt;회원: 일대다 관계&lt;/li&gt;
&lt;li&gt;일대다 관계는 여러 건과 연관관계를 맺을 수 있으므로 컬렉션을 사용해야 함&lt;br /&gt;➡️ JPA는 List, Collection, Set, Map 등의 컬렉션 지원&lt;/li&gt;
&lt;li&gt;데이터베이스 테이블은 외래 키 하나로 양방향 조회 가능&lt;/li&gt;
&lt;li&gt;무한 루프에 빠지지 않게 조심해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 양방향 연관관계 매핑&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731674643666&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Team {
    @Id
    @Column(name=&quot;TEAM_ID&quot;)
    private String id;
    
    @OneToMany(mappedBy=&quot;team&quot;)
    private List&amp;lt;Member&amp;gt; members = new ArrayList&amp;lt;Member&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일대다 관계이기 때문에 팀 엔티티에 컬렉션인 List를 사용&lt;/li&gt;
&lt;li&gt;일대다 관계를 매핑하기 위해 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;@OneToMany&lt;/b&gt;&lt;/span&gt; 매핑 정보 사용&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;mappedBy&lt;/b&gt;&lt;/span&gt; 속성은 양방향 매핑일 때, 반대쪽 매핑의 필드 이름을 값으로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 일대다 컬렉션 조회&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731674886349&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void biDireaction(){
    Team team = em.find(Team.class, &quot;team1&quot;);
    List&amp;lt;Member&amp;gt; members = team.getMembers(); //팀-&amp;gt;회원, 객체그래프 탐색
    
    for(Member member : members){
    	System.out.println(&quot;member.username = &quot; + member.getUsername());
    }
}

//출력결과
//member.username = 회원1&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;   연관관계의 주인&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블은 외래 키 하나로 두 테이블의 연관관계를 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래 키 관리 가능&lt;/li&gt;
&lt;li&gt;엔티티를 양방향으로 매핑 시 두 곳에서 서로를 참조하여, 객체의 연관관계를 관리하는 포인트가 2곳으로 늘어남&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;엔티티를 양방향 연관관계로 설정 시, 객체의 참조는 둘인데 외래 키는 하나여서 차이가 발생&lt;/li&gt;
&lt;li&gt;JPA에서는 두 객체의 연관관계 중 하나를 정해서 테이블의 외래 키를 관리하기 위해 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;연관관계의 주인&lt;/span&gt;&lt;/b&gt;을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 두 연관관계 중 하나를 연관관계의 주인으로 정함&lt;br /&gt;2. 연관관계의 주인만이 &lt;b&gt;데이터베이스 연관관계와 매핑&lt;/b&gt;되고 &lt;b&gt;외래 키를 관리(등록, 수정, 삭제)&lt;/b&gt; 가능&lt;br /&gt;3. 주인이 아닌 쪽은 &lt;b&gt;'읽기'&lt;/b&gt;만 가능&lt;br /&gt;4. 비즈니스 중요도를 배제하고 &lt;b&gt;외래 키의 위치&lt;/b&gt;와 관련해서 설정해야 함&lt;br /&gt;&lt;br /&gt;✅ 주인은 mappedBy 속성 미사용&lt;br /&gt;✅ 주인이 아니면 mappedBy 속성을 사용하여 속성의 값으로 연관관계의 주인을 지정해야 함&lt;br /&gt;✅ 연관관계의 주인은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;외래 키&lt;/b&gt;&lt;/span&gt;가 있는 곳&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;@ManyToOne&lt;/span&gt;은 항상 연관관계의 주인이 되므로, mappedBy를 설정할 수 없음(=mappedBy 속성이 존재하지 않음)&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  양방향 연관관계 저장&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양방향 연관관계는 연과노간계의 주인이 외래 키를 관리하기 때문에 주인이 아닌 방향은 값을 설정하지 않아도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 외래 키 값이 정상 입력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 주인이 아닌 곳에 입력된 값은 외래 키에 영향을 주지 않기 때문에 데이터베이스에 저장할 때 무시된다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  양방향 연관관계의 주의점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 연관관계의 주인에 값 미입력&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연관관계의 주인에는 값을 입력하지 않고, &lt;b&gt;주인이 아닌 곳&lt;/b&gt;에만 값을 입력하는 실수를 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 외래 키 값이 정상적으로 저장되지 않음&lt;/p&gt;
&lt;pre id=&quot;code_1731675596786&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void test() {
    //회원1 저장
    Member member1 = new Member(&quot;member1&quot;, &quot;회원1&quot;);
    em.persist(member1);
    
    //회원2 저장
    Member member2 = new Member(&quot;member2&quot;, &quot;회원2&quot;);
    em.persist(member2);
    
    Team team1 = new Team(&quot;team1&quot;, &quot;팀1&quot;);
    //주인이 아닌 곳만 연관관계 설정
    team1.getMembers().add(member1);
    team1.getMembers().add(member2);
    
    em.persist(team1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 99.9999%; text-align: center;&quot; colspan=&quot;3&quot;&gt;&lt;b&gt;조회결과&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;MEMBER_ID&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;USERNAME&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;TEAM_ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;member1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;회원1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;member2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;회원2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;null&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 순수한 객체까지 고려한 양방향 연관관계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 관점에서 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;양쪽 방향에 모두 값을 입력&lt;/span&gt;&lt;/b&gt;해주는 것이 가장 안전함&lt;/p&gt;
&lt;pre id=&quot;code_1731675850533&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void test(){
    //팀1
    Team team1 = new Team(&quot;team1&quot;, &quot;팀1&quot;);
    Member member1 = new Member(&quot;member1&quot;, &quot;회원1&quot;);
    
    member1.setTeam(team1); //연관관계 설정: member1 -&amp;gt; team1
    team1.getMembers().add(member1); //연관관계 설정: team1 -&amp;gt; member1
    
    List&amp;lt;Member&amp;gt; members = team1.getMembers();
    System.out.println(&quot;members.size = &quot; + members.size()); //출력결과: members.size = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 연관관계 편의 메소드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양방향 관계에서 양쪽 방향에 모두 값을 입력해주는 것을 하나의 코드인 것처럼 사용하는 것이 안전함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연관관계를 변경할 때는 기존의 연관관계를 제거하는 코드가 필요함&lt;/p&gt;
&lt;pre id=&quot;code_1731676024142&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Member {
    private Team team;
    
    public void setTeam(Team team){
    
        //기존 팀과 관계를 제거
        if(this.team != null){
            this.team.getMembers().remove(this);
        }
    
        this.team = team;
        team.getMembers().add(this);
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  정리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단방향 매핑만으로 테이블과 객체의 연관관계 매핑은 이미 완료&lt;/li&gt;
&lt;li&gt;단방향을 양방향으로 만들면 반대방향으로 객체 그래프 탐색 기능이 추가됨&lt;/li&gt;
&lt;li&gt;양방향 연관관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-4106323018420910&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/13</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-10#entry13comment</comments>
      <pubDate>Fri, 15 Nov 2024 22:10:06 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #9</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-9</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.7 필드와 컬럼 매핑: 레퍼런스 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.8 정리 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @Column&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 필드를 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;테이블 컬럼&lt;/span&gt;&lt;/b&gt;에 매핑한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속성 중 name, nullable이 주로 사용되고 나머지는 잘 사용되지 않는 편이다&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 212px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 19px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 19px;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 19px;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 19px;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 19px;&quot;&gt;필드와 매핑할 테이블의 컬럼 이름&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 19px;&quot;&gt;객체의 필드 이름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;nullable&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;null 값의 허용 여부를 설정&lt;br /&gt;false로 설정하면 DDL 생성 시에 not null 제약조건이 붙음&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;unique&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;@Table의 uniqueConstraint와 같지만 한 칼럼에 간단히 유니크 제약조건을 걸 때 사용한다. 만약 두 컬럼 이상을 사용해서 유니크 제약조건을 사용하러며녀 클래스 레벨에서 @Table.uniqueConstraints를 사용해야 한다&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;columnDefinition&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;데이터베이스 칼럼 정보를 직접 줄 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;필드의 자바 타입과 방언 정보를 사용해서 적절한 컬럼 타입을 생성한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;length&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;문자 길이 제약조건, String 타입에만 사용한다&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;precision, scale&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;BigDecimal 타입에서 사용한다&lt;br /&gt;precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다&lt;br /&gt;(double, float 타입에는 적용되지 않음. 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다)&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;precision=19,&lt;br /&gt;scale=2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 17px;&quot;&gt;table&lt;br /&gt;(거의 사용하지 않음)&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 17px;&quot;&gt;하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용한다&lt;br /&gt;지정한 필드를 다른 테이블에 매핑할 수 있다&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 17px;&quot;&gt;현재 클래스가 매핑된 테이블&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 36px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 36px;&quot;&gt;insertable&lt;br /&gt;(거의 사용하지 않음)&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 36px;&quot;&gt;엔티티 저장 시 이 필드도 같이 저장한다&lt;br /&gt;false로 설정 시 이 필드는 데이터베이스에 저장하지 않음 (=읽기 전용)&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 36px;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 36px;&quot;&gt;
&lt;td style=&quot;width: 23.3333%; height: 36px;&quot;&gt;updatable&lt;br /&gt;(거의 사용하지 않음)&lt;/td&gt;
&lt;td style=&quot;width: 53.9147%; height: 36px;&quot;&gt;엔티티 수정 시 이 필드도 같이 수정한다&lt;br /&gt;false로 설정 시 이 필드는 데이터베이스에 수정하지 않음 (= 읽기 전용)&lt;/td&gt;
&lt;td style=&quot;width: 22.7519%; height: 36px;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731414762327&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//nullable
@Column(nullable=false)
private Strign data;
=&amp;gt; data varchar(255) not null

//unique
@Column(unique=true)
private String username;
=&amp;gt; alter table Tablename add constraint UK_Xxx unique(uesrname)

//columnDefinition
@Column(columnDefinition=&quot;varchar(100) default 'EMPTY'&quot;)
private String data;
=&amp;gt; DDL: datda varchar(100) default 'EMPTY'

//length
@Column(length=400)
private String data;
=&amp;gt; DDL: data varchar(400)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Column 생략&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생략 시 대부분 @Column 속성의 기본값이 적용되는데, 자바 기본 타입일 때는 nullable 속성에 예외가 있음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;자바 기본 타입&lt;/span&gt;(ex. int)에는 NULL 값을 입력할 수 없음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 기본 타입을 DDL로 생성 시 not null 제약 조건을 추가하는 것이 안전함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체 타입&lt;/span&gt;(ex. Integer)에는 NULL값이 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @Enumerated&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 enum 타입을 매핑할 때 사용한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 44px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 19.6124%; height: 10px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 47.0542%; height: 10px;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 10px;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 19.6124%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;value&lt;/td&gt;
&lt;td style=&quot;width: 47.0542%; height: 17px;&quot;&gt;EnumType.ORDINAL: enum 순서를 데이터베이스에 저장&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;EnumType.ORDINAL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 47.0542%; height: 17px;&quot;&gt;EnumType.STRING: enum 이름을 데이터베이스에 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731415216192&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum RoleType{
	ADMIN, USER
}

//enum 이름으로 매핑
@Enumerated(EnumType.STRING)
private RoleType roleType;

//사용법
member.setRoleType(RoleType.ADMIN)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EnumType.ORDINAL : enum에 정의된 순서대로 0부터 값이 데이터베이스에 저장됨&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 데이터베이스에 저장되는 데이터 크기가 작다&lt;/li&gt;
&lt;li&gt;단점: 이미 저장된 enum의 순서를 변경할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;EnumType.STRING : enum 이름 그대로의 문자가 데이터베이스에 저장됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전함&lt;/li&gt;
&lt;li&gt;단점: 데이터베이스에 저장되는 데이터 크기가 ORDINAL에 비해서 큼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  &lt;b&gt;주의&lt;/b&gt;&lt;br /&gt;enum의 순서가 바뀌게 될 경우, 이후에는 바뀐 데이터 값으로 저장되지만&lt;br /&gt;기존에 데이터베이스에 저장된 값은 바뀌지 않고 여전히 유지되고 있기 때문에 &lt;br /&gt;이러한 문제가 발생하지 않는 EnumType.STRING을 권장함.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @Temporal&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;날짜타입을 매핑할 때 사용한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.8449%;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.8217%;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.8449%;&quot; rowspan=&quot;3&quot;&gt;value&lt;/td&gt;
&lt;td style=&quot;width: 51.8217%;&quot;&gt;TemporalType.DATE&lt;br /&gt;날짜, 데이터베이스 date 타입과 매핑 (예: 2024-11-12)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot; rowspan=&quot;3&quot;&gt;TemporalType은 필수로 지정해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 51.8217%;&quot;&gt;TemporalType.TIME&lt;br /&gt;시간, 데이터베이스 time 타입과 매핑 (예: 11:11:11)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 51.8217%;&quot;&gt;TemporalType.TIMESTAMP&lt;br /&gt;날짜와 시간, 데이터베이스 timestamp 타입과 매핑&amp;nbsp;&lt;br /&gt;(예: 2024-11-12 11:11:11)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;datetime: MySQL&lt;/li&gt;
&lt;li&gt;timestamp: H2, Oracle, PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @Lob&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 BLOB, CLOB 타입과 매핑한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지정할 수 있는 속성이 없음. 대신 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB로 매핑한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CLOB: String, char[], java.sql.CLOB&lt;/li&gt;
&lt;li&gt;BLOB: byte[], java.sql.BLOB&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @Transient&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 필드는 매핑하지 않기 때문에 데이터베이스에 저장하지 않고 조회하지도 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체에 임시로 어떤 값을 보관하고 싶을 때 사용&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  @ Access&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA가 엔티티 데이터에 접근하는 방식을 지정한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Access를 설정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정됨&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;필드 접근&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AccessType.FIELD&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;필드에 직접 접근하며, 필드 접근 권한이 private여도 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로퍼티 접근&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AccessType.PROPERTY&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;접근자(Getter)를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;필드 접근 방식 + 프로퍼티 접근 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731416602909&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member{
    @Id
   	private String id;
    
    @Access(AccessType.PROPERTY)
    public String getFullName(){
    	return firstNmae + lastName;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Id가 필드에 있으므로 기본은 필드 접근 방식 사용&lt;/li&gt;
&lt;li&gt;getFullName()만 프로퍼티 접근 방식 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  정리&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;분류&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매핑 어노테이션&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot; rowspan=&quot;5&quot;&gt;필드와 컬럼 매핑&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Column&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;컬럼을 매핑한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Enumerated&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;자바의 enum 타입을 매핑한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Temporal&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;날짜 타입을 매핑한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Lob&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;BLOB, CLOB 타입을 매핑한다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Transient&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;특정 필드를 데이터베이스에 매핑하지 않는다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;기타&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;@Access&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;JPA가 엔티티에 접근하는 방식을 지정한다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-4106323018420910&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/12</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-9#entry12comment</comments>
      <pubDate>Tue, 12 Nov 2024 22:04:14 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #8</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-8</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.6 기본키 매핑 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  데이터베이스 기본 키 생성 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 할당
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키를 애플리케이션에서 직접 할당&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@Id&lt;/b&gt; 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자동 생성 (=대리 키 사용 방식)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@Id + @GeneratedValue&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;IDENTITY&lt;/span&gt;&lt;/b&gt; : 기본 키 생성을 데이터베이스에 위임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;SEQUENCE&lt;/span&gt;&lt;/b&gt; : 데이터베이스 시퀀스를 사용해서 기본 키를 할당&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;TABLE&lt;/span&gt;&lt;/b&gt; : 키 생성 테이블을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  기본 키 직접 할당 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매핑 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;@Id&lt;/span&gt;&lt;/b&gt; 로 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731333995294&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Id
@Column(name = &quot;id&quot;)
private String id;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적용 가능한 자바 타입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 기본형&lt;/li&gt;
&lt;li&gt;자바 래퍼(Wrapper)형&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;li&gt;java.util.Date&lt;/li&gt;
&lt;li&gt;java.sql.Date&lt;/li&gt;
&lt;li&gt;java.math.BigDecimal&lt;/li&gt;
&lt;li&gt;java.math.BigInteger&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  IDENTITY 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 키 생성을 데이터베이스에 위임하는 전략&lt;/li&gt;
&lt;li&gt;사용 가능한 데이터베이스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL, PostgreSQL, SQL Server, DB2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용&lt;/li&gt;
&lt;li&gt;매핑 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731334455605&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDENTITY 전략과 최적화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 데이터베이스에 INSERT한 후에 기본 키 값을 조회 가능&lt;br /&gt;➡️ 엔티티에 식별자 값을 할당하려면 JPA는 추가로 데이터베이스를 조회해야 함&lt;/li&gt;
&lt;li&gt;JDBC3에 추가된 Statement.getGeneratedKeys()를 사용하면 데이터를 저장하면서 동시에 생성된 기본 키 값도 얻을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션을 지원하는 &lt;b&gt;쓰기 지연이 동작하지 않음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티가 영속 상태가 되려면 식별자가 반드시 필요&lt;/li&gt;
&lt;li&gt;IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 persist()를 호출하는&lt;br /&gt;즉시 INSERT SQL이 데이터베이스에 전달됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  SEQUENCE 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시퀀스를 사용해서 기본 키를 생성&lt;/li&gt;
&lt;li&gt;사용 가능한 데이터베이스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오라클, PostgreSQL, DB2, H2 데이터베이스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;매핑 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731335225554&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@SequenceGenerator (
    name = &quot;BOARD_SEQ_GENERATOR&quot;,
    sequenceName = &quot;BOARD_SEQ&quot;,	//매핑할 데이터베이스 시퀀스 이름
    initialValue = 1, allocationSize = 1)
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
    				generator = &quot;BOARD_SEQ_GENERATOR&quot;)
    private Long id;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;persist() 호출 시 먼저 데이터베이스 시퀀스를 사용해서 식별자 조회&lt;br /&gt;➡️ 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&amp;nbsp;@SequenceGenerator&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;식별자 생성기 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;sequenceName&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;데이터베이스에 등록되어 있는 시퀀스 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;hibernate_sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;initialValue&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;DDL 생성 시에만 사용됨.&lt;br /&gt;시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;allocationSize&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;시퀀스 한 번 호추렝 증가하는 수 (성능 최적화에 사용됨)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;50&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.7752%;&quot;&gt;catalog, schema&lt;/td&gt;
&lt;td style=&quot;width: 45.8914%;&quot;&gt;데이터베이스 catalog, schema 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  SequenceGenerator.allocationSize의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;기본값 = 50&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;시퀀스를 호출할 때마다 값이 50씩 증가 ➡️&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;최적화&lt;/span&gt;&amp;nbsp;때문에 사용&lt;br /&gt;&lt;br /&gt;&lt;b&gt;SEQUENCE 전략 방법 (= 데이터베이스 2번 통신)&lt;/b&gt;&lt;br /&gt;1. 식별자를 구하려고 데이터베이스 시퀀스를 조회&lt;br /&gt;2. 조회한 시퀀스를 기본 키값으로 사용해 데이터베이스에 저장&lt;br /&gt;&lt;br /&gt;JPA는 시퀀스에 접근하는 횟수를 줄이기 위해, 여기에 설정한 값만큼 한 번에 시퀀스 값을 증가시키고 나서&lt;br /&gt;그만큼 메모리에 시퀀스 값을 할당&lt;br /&gt;&lt;br /&gt;최적화  예) allocationSize 값이 50이면, 시퀀스를 한 번에 50 증가시킨 다음에 1~50까지는 메모리에서 식별자를 할당&lt;br /&gt;➡️시퀀스 값을 선점하므로 여러 JVM이 동시에 동작해도 기본 키 값이 충돌하지 않는 장점&lt;br /&gt;&lt;br /&gt;데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두&lt;br /&gt;➡️ 이런 상황이 부담스럽고, INSERT 성능이 중요하지 않으면 allocationSize의 값을 1로 설정&lt;br /&gt;&lt;br /&gt;hibernate.id.new_generator_mapperings 속성을 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;true&lt;/span&gt;&lt;/b&gt;로 설정해야 최적화 방법이 적용됨&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  TABLE 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략&lt;/li&gt;
&lt;li&gt;모든 데이터베이스에 적용 가능&lt;/li&gt;
&lt;li&gt;코드 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731336540317&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@TableGenerator(
    name = &quot;BOARD_SEQ_GENERATOR&quot;,
    table = &quot;MY_SEQUENCES&quot;,
    pkCloumnValue = &quot;BOARD_SEQ&quot;, allocationSize = 1)
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
    				generator = &quot;BOARD_SEQ_GENERATOR&quot;)
    private Long id;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TABLE 전략은 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 같음&lt;/li&gt;
&lt;li&gt;테이블에 값이 없으면 JPA가 값을 INSERT하면서 초기화하므로 값을 미리 넣어둘 필요는 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@TableGenerator&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 182px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 20px;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 20px;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;식별자 생성기 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;table&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;키생성 테이블명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;hibernate_sequences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;pkColumnName&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;시퀀스 컬럼명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;sequence_name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;valueColumnName&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;시퀀스 값 컬럼명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;next_val&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;pkCoumnValue&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;키로 사용할 값 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;엔티티 이름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;initialValue&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;초기 값, 마지막으로 생성된 값이 기준&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;allocationSize&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;시퀀스 한 번 호출에 증가하는 수&lt;br /&gt;(성능 최적화에 사용됨)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;catalog, schema&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;데이터베이스 catalog, schema 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 26.5891%; height: 18px;&quot;&gt;uniqueConstraints(DDL)&lt;/td&gt;
&lt;td style=&quot;width: 40.0775%; height: 18px;&quot;&gt;유니크 제약 조건 지정 가능&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;TABLE 전략과 최적화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;값을 조회하면서 SELECT 쿼리를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리 사용&lt;/li&gt;
&lt;li&gt;이 전략을 SEQUENCE 전략과 비교해서 데이터베이스와 한 번 더 통신하는 단점 있음&lt;/li&gt;
&lt;li&gt;최적화하려면 @TableGenerator.allocationSize 사용 ➡️ SEQUENCE 전략과 방법은 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  AUTO 전략&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택&lt;/li&gt;
&lt;li&gt;데이터베이스를 변경해도 코드를 수정할 필요가 없다는 장점&lt;/li&gt;
&lt;li&gt;스키마 자동 생성 기능을 사용 시 하이버네이트가 기본값을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만들어 줌&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  기본 키 매핑 정리&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;직접 할당&lt;br /&gt;persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 함&lt;br /&gt;식별자 값이 없으면 예외가 발생&lt;/li&gt;
&lt;li&gt;SEQUENCE&lt;br /&gt;데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;li&gt;TABLE&lt;br /&gt;데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;li&gt;IDENTITY&lt;br /&gt;데이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장&lt;br /&gt;(IDENTITY 전략은 테이블에 데이터를 저장해서 식별자 값을 획득할 수 있음)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;권장하는 식별자 선택 전략&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 키 조건 충족 필요&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;NULL값 허용하지 않음&lt;/li&gt;
&lt;li&gt;유일해야 함&lt;/li&gt;
&lt;li&gt;변해서는 안됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 키를 선택하는 전략&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;자연 키(natural Key) : 비즈니스에 의미가 있는 키&lt;/li&gt;
&lt;li&gt;대리 키(surrogate key) : 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불림&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  기본 키는 변하면 안 된다는 기본 원칙으로 인해, 저장된 엔티티의 기본 키 값은 절대 변경하면 안됨&lt;br /&gt;이 경우 JPA는 예외를 발생시키거나 정상 동작하지 않음&lt;br /&gt;➡️&amp;nbsp; setId() 같이 식별자를 수정하는 메소드를 외부에 공개하지 않는 것도 문제를 예방하는 하나의 방법이 될 수 있음&lt;/blockquote&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/11</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-8#entry11comment</comments>
      <pubDate>Mon, 11 Nov 2024 23:52:13 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #7</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-7</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.1 @Entity ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.2 @Table ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.3 다양한 매핑 사용 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.4 데이터베이스 스키마 자동 생성 ✅&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4.5 DDL 생성 기능 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JPA에서 제공하는 다양한 매핑 어노테이션&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체와 테이블 매핑: @Entity, @Table&lt;/li&gt;
&lt;li&gt;기본 키 매핑: @Id&lt;/li&gt;
&lt;li&gt;필드와 컬럼 매핑: @Column&lt;/li&gt;
&lt;li&gt;연관관계 매핑: @ManyToOne, @JoinColumn&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt; @Entity&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JPA를 사용해서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;테이블과 매핑할 클래스&lt;/span&gt;는 @Entity 어노테이션을 필수로 붙여야 함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 어노테이션이 붙은 클래스는 JPA가 관리하는 것으로 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;'엔티티'&lt;/span&gt;&lt;/b&gt;라 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA에서 사용할 엔티티 이름 지정&lt;/li&gt;
&lt;li&gt;보통 기본값인 클래스 이름 사용&lt;/li&gt;
&lt;li&gt;다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름을 지정해서 충돌하지 않도록 수정 필요&lt;/li&gt;
&lt;li&gt;기본값을 설정하지 않으면 클래스 이름을 그대로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;주의사항&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 기본 생성자는 필수(파라미터가 없는 public 또는 protected 생성자)&lt;br /&gt;➡️ 생성자를 하나 이상 만들면 자바는 기본 생성자를 자동으로 만들지 않기 때문에, 기본 생성자를 직접 만들어야 함&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731244123761&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Member(){} //직접 만든 기본 생성자

//임의의 생성자
public Member(String name){
	this.name = name
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;fianl 클래스, enum, interface, inner 클래스에는 사용 불가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 저장할 필드에 final을 사용하면 안됨&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt; @Table&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;엔티티와 매핑할 테이블을 지정하고, 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;name
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매핑할 테이블의 이름&lt;/li&gt;
&lt;li&gt;엔티티 이름을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;catalog
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;catalog 기능이 있는 데이터베이스에서 catalog를 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;schema&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;schema 기능이 있는 데이터베이스에서 schema를 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;uniqueConstraints(DDL)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDL 생성 시에 유니크 제약 조건 생성&lt;/li&gt;
&lt;li&gt;2개 이상의 복합 유니크 제약조건도 만들 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;다양한 매핑 사용&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731244527666&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Table(name=&quot;MEMBER&quot;)
public class Member{
	@Enumerated(EnumType.STRING)
    private RoleType roleType;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Lob
    private String description;
    
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바의 enum을 사용하려면 &lt;b&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;@Eunmerated&lt;/span&gt;&lt;/b&gt; 어노테이션으로 매핑 필요&lt;/li&gt;
&lt;li&gt;자바의 날짜 타입은 &lt;b&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;@Temporal&lt;/span&gt;&lt;/b&gt;을 사용하여 매핑&lt;/li&gt;
&lt;li&gt;길이 제한이 없는 필드는 데이터베이스의 VARCHAR 타입 대신에 CLOB 타입으로 저장 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;@Lob&lt;/span&gt;&lt;/b&gt; 사용 시 CLOB, BLOB 타입 매핑 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt; 데이터베이스 스키마 자동 생성&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원하며,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;클래스의 매핑 정보를 보면 어떤 테이블에 어떤 컬럼을 사용했는지 확인 가능&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;➡️ 이 매핑정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스키마 자동 생성 기능 사용법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;persistence.xml에 다음 속성 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731244927726&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;property name=&quot;hibernate.hbm2ddl.auto&quot; value=&quot;create&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;hibernate.show_sql&lt;/span&gt;속성을 true 설정 시 콘솔에 실행되는 테이블 생성 DDL을 출력 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;hibernate.hbm2ddl.auto 속성&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.186%;&quot;&gt;create&lt;/td&gt;
&lt;td style=&quot;width: 75.814%;&quot;&gt;기존 테이블을 삭제하고 새로 생성 (DROP + CREATE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.186%;&quot;&gt;create-drop&lt;/td&gt;
&lt;td style=&quot;width: 75.814%;&quot;&gt;create 속성에 추가로 애플리케이션을 종료할 때 생성한 DDL을 제거 (DROP + CREATE + DROP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.186%;&quot;&gt;update&lt;/td&gt;
&lt;td style=&quot;width: 75.814%;&quot;&gt;데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.186%;&quot;&gt;validate&lt;/td&gt;
&lt;td style=&quot;width: 75.814%;&quot;&gt;데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 넘기고 애프리케이션을 실행하지 않음. 이 설정은 DDL을 수정하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.186%;&quot;&gt;none&lt;/td&gt;
&lt;td style=&quot;width: 75.814%;&quot;&gt;자동 생성 기능을 사용하지 않으면 hibernate.hbm2ddl.auto속성 자체를 삭제하거나 유효하지 않은 옵션 값을 주면 됨 (참고로 none은 유효하지 않은 옵션임)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;주의사항
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;create, create-drop, update처럼 DDL을 수정하는 옵션은 오직 개발 서버나 개발 단계에서만 사용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;참고사항
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JPA는 2.1부터 스키마 자동 생성 기능을 표준으로 지원&lt;/li&gt;
&lt;li&gt;자바는 카멜 표기법 사용, 데이터베이스는 언더스코어(_)를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;DDL 생성기능&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731246012211&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Table(name=&quot;MEMBER&quot;)
public class Member{
	@Id
    @Column(name=&quot;ID&quot;)
    private Strign id;
    
    @Column(name=&quot;NAME&quot;, nullable = false, length = 10)
    private String username;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Colunm 매핑 정보
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nullabe 속성 값 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDL에 NOT NULL 제약조건 추가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;length 속성 값 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDL에 문자의 크기 지정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 이런 기능들은 단지 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않음&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/10</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-7#entry10comment</comments>
      <pubDate>Sun, 10 Nov 2024 22:41:54 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #6</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-6</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.5 플러시 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.6 준영속 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.7 정리 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;플러시&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트의 변경 내용을 데이터베이스에 반영&lt;/li&gt;
&lt;li&gt;플러시는 영속성 컨텍스트에 보관된 엔티티를 지우는 것이 아니라, 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화&lt;/li&gt;
&lt;li&gt;실행 과정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교하여 수정된 엔티티를 찾음&lt;/li&gt;
&lt;li&gt;수정된 엔티티는 수정 쿼리를 만들어 쓰기 지연 SQL 저장소에 등록&lt;/li&gt;
&lt;li&gt;쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트 플러시 방법&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;flush()&lt;/span&gt;&lt;/b&gt;를 직접 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트나 다름 프레임워크와 JPA를 함께 사용할 때 제외하고 거의 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 커밋 시&lt;/b&gt; 플러시 자동 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스에 변경 내용을 SQL로 전달하지 않고 트랜잭션만 커밋 시 데이터베이스에 반영되지 않음&lt;/li&gt;
&lt;li&gt;트랜잭션을 커밋 시 플래시를 자동 호출하여 해당 문제 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JPQL 쿼리 실행 시&lt;/b&gt; 플러시가 자동 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPQL이나 Criteria 같은 객체지향 쿼리를 호출할 때도 플러시 자동 실행&lt;/li&gt;
&lt;li&gt;쿼리 실행 직전에 영속성 컨텍스트를 플러시해서 변경 내용을 데이터베이스에 반영해야 하는 문제를 예방하기 위함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;플러시 모드 옵션
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 지정 시, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;javax.persistence.FlustModeTyp&lt;/span&gt;e 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;FlustModType.AUTO&lt;/b&gt;&lt;/span&gt; : 커밋이나 쿼리를 실행할 때 플러시(기본값)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;FlustModeType.COMMIT&lt;/b&gt;&lt;/span&gt; : 커밋할 때만 플러시 ➡️ 성능 최적화를 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;준영속&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없음&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;준영속 상태로 만드는 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;detach(entity)&lt;/span&gt; : 특정 엔티티만 준영속 상태로 전환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 메서드를 호출하는 순간, 1차 캐시부터 쓰기 지연 SQL 저장소까지 해당 엔티티를 관리하기 위한 모든 정보 제거&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트가 지원하는 어떤 기능도 동작하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;clear()&lt;/span&gt; : 영속성 컨텍스트를 완전히 초기화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트를 초기화해서 해당 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 전환&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트가 제공하는 변경 감지는 동작하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;close()&lt;/span&gt; : 영속성 컨텍스트를 종료
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 영속성 컨텍스트가 관리하던 영속 상태의 엔티티가 모두 준영속 상태로 전환&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;영속 상태의 엔티티는 주로 &lt;b&gt;영속성 컨텍스트가 종료되면서 준영속 상태&lt;/b&gt;가 되기 때문에,&lt;br /&gt;개발자가 직접 준영속 상태로 만드는 일은 드물다&lt;/li&gt;
&lt;li&gt;준영속 상태의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;거의 비영속에 가까움&lt;/span&gt;: 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않음&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;식별자 값&lt;/span&gt;을 가지고 있음: 이미 한 번 영속 상태였으므로 반드시 식별자 값을 가지고 있음&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;지연 로딩 불가능&lt;/span&gt;: 지연 로딩은 실제 객체 대신 프록시 객체를 로딩해두고 해당 객체를 실제 사용할 때 영속성 컨텍스트를 통해 데이터를 불러오는 방법이나, 영속 상태는 영속성 컨텍스트가 더는 관리하지 않기 때문에 지연 로딩 시 문제 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;준영속 병합
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;준영속 상태의 엔티티를 다시 영속 상태로 변경&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;merge()&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;준영속 상태의 엔티티를 받아서 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;그 정보로 새로운 영속 상태의 엔티티&lt;/b&gt;&lt;/span&gt;를 반환&lt;/li&gt;
&lt;li&gt;동작 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0162.jpg&quot; data-origin-width=&quot;4028&quot; data-origin-height=&quot;2760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iz2ts/btsKCNPx2tb/2xRFZwwrQw2JsioNFKKvH0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iz2ts/btsKCNPx2tb/2xRFZwwrQw2JsioNFKKvH0/img.jpg&quot; data-alt=&quot;[그림1] 준영속 병합 - merge() 동작 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iz2ts/btsKCNPx2tb/2xRFZwwrQw2JsioNFKKvH0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIz2ts%2FbtsKCNPx2tb%2F2xRFZwwrQw2JsioNFKKvH0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4028&quot; height=&quot;2760&quot; data-filename=&quot;IMG_0162.jpg&quot; data-origin-width=&quot;4028&quot; data-origin-height=&quot;2760&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림1] 준영속 병합 - merge() 동작 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;merge() 를 실행&lt;/li&gt;
&lt;li&gt;파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티 조회
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;만약 1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고 1차 캐시에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;조회한 영속 엔티티에 member 엔티티의 값을 채워 넣음
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;member 엔티티의 모든 값을 mergeMember에 밀어 넣음&lt;/li&gt;
&lt;li&gt;이때 mergeMember의 &quot;회원1&quot; 라는 이름이 &quot;회원명변경&quot;으로 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;mergeMember 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비영속 병합
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병합은 준영속, 비영속을 신경쓰지 않음&lt;/li&gt;
&lt;li&gt;식별자 값으로 엔티티를 조회할 수 있으면 불러서 병합&lt;/li&gt;
&lt;li&gt;조회가 불가능하면 새로 생성해서 병합 ➡️ save or update 기능 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  정리&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;엔티티 매니저&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;엔티티 매니저 팩토리에서 생성&lt;/li&gt;
&lt;li&gt;엔티티 매니저의 내부에 영속성 컨텍스트도 함께 만들어 짐&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트는 엔티티 매니저를 통해 접근 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영속성 컨텍스트&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;애플리케이션과 데이터베이스 사이에 객체를 보관하는 가상의 데이터베이스 같은 역할&lt;/li&gt;
&lt;li&gt;1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기 지연, 변경 감지, 지연 로딩 기능 등 사용 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플러시&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;영속성 컨텍스트에 저장한 엔티티가 데이터베이스에 반영되는 것&lt;/li&gt;
&lt;li&gt;트랜잭션을 커밋 시 영속성 컨텍스트가 플러시 됨&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영속/준영속 상태의 엔티티&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;영속성 컨텍스트가 관리하는 엔티티&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트가 관리하지 않는 엔티티는 준영속 상태의 엔티티&lt;/li&gt;
&lt;li&gt;준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능들(2-2 참고) 사용 불가능&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;엔티티 매니저와 영속성 컨텍스트는 매핑한 엔티티를 실제 사용하는 동적인 부분에 해당&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/9</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-6#entry9comment</comments>
      <pubDate>Sat, 9 Nov 2024 22:35:21 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #5</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-5</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.1 엔티티 매니저 팩토리와 엔티티 매니저 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.2 영속성 컨텍스트란? ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.3 엔티티의 생명주기 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3.4 영속성 컨텍스트의 특징 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;엔티티 매니저 팩토리와 엔티티 매니저&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA 제공 기능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티와 테이블을 매핑하는 설계 부분&lt;/li&gt;
&lt;li&gt;매핑한 엔티티를 실제 사용하는 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;엔티티 매니저(Entity Manager)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티를 저장하는 가상의 데이터베이스&lt;/li&gt;
&lt;li&gt;생성하는 비용이 거의 들지 않음&lt;/li&gt;
&lt;li&gt;여러 스레드가 동시에 접근하면 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;동시성 문제&lt;/b&gt;&lt;/span&gt;가 발생 ➡️ &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스레드 간에 절대 공유하면 안됨&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;엔티티 매니저 팩토리(Entity Manager Factory)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 매니저를 만듦&lt;/li&gt;
&lt;li&gt;데이터베이스를 하나만 사용하는 애플리케이션은 일본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;EntityManagerFactory&lt;/span&gt;를 하나만 생성&lt;/li&gt;
&lt;li&gt;비용이 아주 많이 들기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 개&lt;/b&gt;만 만들어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;애플리케이션 전체에 공유&lt;/b&gt;하도록 설계&lt;/li&gt;
&lt;li&gt;여러 스레드가 동시에 접근해도 안전 ➡️ &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;서로 다른 스레드 간에 공유 가능&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;커넥션 획득 시기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0147.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F4nbP/btsKC5INIe3/Sjp3y8p7PsNs8jUDK0uu61/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F4nbP/btsKC5INIe3/Sjp3y8p7PsNs8jUDK0uu61/img.jpg&quot; data-alt=&quot;[그림1] 일반적인 웹 애플리케이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F4nbP/btsKC5INIe3/Sjp3y8p7PsNs8jUDK0uu61/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF4nbP%2FbtsKC5INIe3%2FSjp3y8p7PsNs8jUDK0uu61%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;2320&quot; data-filename=&quot;IMG_0147.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2320&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림1] 일반적인 웹 애플리케이션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;엔티티 매니저&lt;/b&gt;는 데이터베이스 연결이 꼭 필요한 시점까지 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;커넥션을 얻지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커넥션풀&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하이버네이트를 포함한 JPA 구현체들은 엔티티 매니저 팩토리를 생성할 때 만듦&lt;/li&gt;
&lt;li&gt;J2SE 환경에서 사용하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;영속성 컨텍스트란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트(Persistence context)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티를 영구 저장하는 환경&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;엔티티 매니저를 생성할 때 하나 만들어짐&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;persist()&lt;/span&gt; 메서드 : 엔티티 매니저를 사용해서 엔티티를 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;li&gt;엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있고, 영속성 컨텍스트 관리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;엔티티 생명주기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_150.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvlZ5O/btsKDZVlTTx/K2Xm8dObYPtgvBKRDpx9MK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvlZ5O/btsKDZVlTTx/K2Xm8dObYPtgvBKRDpx9MK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvlZ5O/btsKDZVlTTx/K2Xm8dObYPtgvBKRDpx9MK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvlZ5O%2FbtsKDZVlTTx%2FK2Xm8dObYPtgvBKRDpx9MK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;2462&quot; data-filename=&quot;IMG_150.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티의 &lt;b&gt;4가지&lt;/b&gt; 상태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비영속(new/tranient): 영속성 컨텍스트와 전혀 관계가 없는 상태&lt;/li&gt;
&lt;li&gt;영속(managed): 영속성 컨텍스트에 저장된 상태&lt;/li&gt;
&lt;li&gt;준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태&lt;/li&gt;
&lt;li&gt;삭제(removed): 삭제된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 비영속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 객체를 생성했지만 순수한 객체 상태이며 아직 저장되지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트나 데이터베이스와는 전혀 관련이 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 영속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;영속성 컨텍스트가 관리하는 엔티티를 영속 상태&lt;/span&gt;라 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 영속 상태라는 것은 &lt;b&gt;영속성 컨텍스트에 의해 관리된다&lt;/b&gt;는 뜻&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 준영속&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트가 관리하던 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않는 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;준영속성 상태로 만들기 위한 방법&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;detach()&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;close()&lt;/span&gt; : 영속성 컨텍스트 닫기&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;clear()&lt;/span&gt; : 영속성 컨텍스트 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트와 데이터베이스에서 삭제&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;remove()&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;영속성 컨텍스트의 특징&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티를 식별자로 구분&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;영속 상태는 식별자의 값이 반드시 필요&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플러시(flush)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;새로 저장한 엔티티를 데이터베이스에 반영&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트가 엔티티를 관리할 때의 장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 캐시&lt;/li&gt;
&lt;li&gt;동일성 보장&lt;/li&gt;
&lt;li&gt;트랜잭션을 지원하는 쓰기 지연&lt;/li&gt;
&lt;li&gt;변경 감지&lt;/li&gt;
&lt;li&gt;지연 로딩&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;엔티티 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;1차 캐시
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;영속성 컨텍스트가 내부에 가지고 있는 캐시&lt;/li&gt;
&lt;li&gt;영속 상태의 엔티티는 모두 1차 캐시에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트 내부의 Map
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;키: &lt;span style=&quot;background-color: #dddddd;&quot;&gt;@Id&lt;/span&gt;로 매핑한 식별자&lt;/li&gt;
&lt;li&gt;값: 엔티티 인스턴스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;persist()&lt;/span&gt;를 하면 1차 캐시에 해당 엔티티를 저장할 뿐, 아직 데이터베이스에 저장되지 않음&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트에 데이터를 저장하고 조회하는 모든 기준은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;데이터베이스 기본 키 값&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 1차 캐시에서 조회&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0149.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2073&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sQh6r/btsKDqslyrR/5txhUXJSORUSSxzrRkO2J0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sQh6r/btsKDqslyrR/5txhUXJSORUSSxzrRkO2J0/img.jpg&quot; data-alt=&quot;[그림2] 1차 캐시에서 조회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sQh6r/btsKDqslyrR/5txhUXJSORUSSxzrRkO2J0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsQh6r%2FbtsKDqslyrR%2F5txhUXJSORUSSxzrRkO2J0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;2073&quot; data-filename=&quot;IMG_0149.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2073&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림2] 1차 캐시에서 조회&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;find()를 호출하면 우선 1차 캐시에서 식별자 값으로 엔티티를 찾음&lt;/li&gt;
&lt;li&gt;찾는 엔티티가 있으면 데이터베이스를 조회하지 않고 메모리에 있는 1차 캐시에서 엔티티 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;✅ 데이터베이스에서 조회&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0150.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;1572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caJHIT/btsKB4RVZVr/c7H5mQKVrhDkkTAI2GaVVK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caJHIT/btsKB4RVZVr/c7H5mQKVrhDkkTAI2GaVVK/img.jpg&quot; data-alt=&quot;[그림3] 1차 캐시에 없어 데이터베이스 조회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caJHIT/btsKB4RVZVr/c7H5mQKVrhDkkTAI2GaVVK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaJHIT%2FbtsKB4RVZVr%2Fc7H5mQKVrhDkkTAI2GaVVK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;1572&quot; data-filename=&quot;IMG_0150.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;1572&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림3] 1차 캐시에 없어 데이터베이스 조회&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1차 캐시에 없으면 엔티티 매니저는 데이터베이스를 조회해서 엔티티 생성&lt;/li&gt;
&lt;li&gt;1차 캐시에 저장한 후에 영속 상태의 엔티티를 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  분석&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;find()를 실행&lt;/li&gt;
&lt;li&gt;1차 캐시에 없으므로 데이터베이스에서 조회&lt;/li&gt;
&lt;li&gt;조회한 데이터로 엔티티를 생성해서 1차 캐시에 저장(=영속 상태)&lt;/li&gt;
&lt;li&gt;조회한 엔티티를 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 엔티티 인스턴스가 1차 캐시에 있을 경우, 이 엔티티를 조회하면 메모리에 있는 1차 캐시에서 바로 불러옴.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;성능상 이점&lt;/b&gt;&lt;/span&gt;을 누릴 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;➡️ 반복해서 find()를 호출해도 영속성 컨텍스트는 1차 캐시에 있는 같은 엔티티 인스턴스를 반환하기 때문에&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;엔티티의 동일성을 보장&lt;/b&gt;&lt;/span&gt;함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;엔티티 등록&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰기 지연(transactioanl write-behind)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 매니저는 트랜잭션을 커밋하기 직전까지 데이터베이스에 엔티티를 저장하지 않고 내부 쿼리 저장소에 모음&lt;/li&gt;
&lt;li&gt;트랜잭션 커밋 시 모아둔 쿼리를 데이터베이스에 내보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 데이터베이스에 쿼리를 한 번에 전달해서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;성능을 최적화&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플러시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션을 커밋하면 엔티티 매니저는 우선 영속성 컨텍스트 플러시&lt;/li&gt;
&lt;li&gt;플러시란 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업&lt;/li&gt;
&lt;li&gt;등록, 수정, 삭제한 엔티티를 데이터베이스에 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;엔티티 수정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경 감지(dirty checking)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변경 감지 순서
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션을 커밋 시 엔티티 매니저 내부에서 플러시 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;엔티티와 스냅샷을 비교해서 변경된 엔티티를 찾음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스냅샷: 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해둠&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변경된 엔티티가 있으면 수정 쿼리를 생성해서 쓰기 지연 SQL 저장소에 보냄&lt;/li&gt;
&lt;li&gt;쓰기 지연 저장소의 SQL을 데이터베이스에 보냄&lt;/li&gt;
&lt;li&gt;데이터베이스 트랜잭션을 커밋&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;변경 감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용됨&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티의 모든 필드를 업데이트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 필드를 사용하면 수정 쿼리가 항상 같음&lt;/li&gt;
&lt;li&gt;데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱된 쿼리 재사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 필드 사용 시 데이터베이스에 보내는 데이터 전송량이 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;필드가 많거나 저장된 내용이 너무 크면 수정된 데이터만 사용해서 동적으로 UPDATE SQL을 생성하는 전략 선택&lt;br /&gt;➡️ 하이버네이트 확장 기능 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;b&gt;엔티티 삭제&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;remove()에 삭제 대상 엔티티를 넘겨주면 엔티티를 삭제&lt;/li&gt;
&lt;li&gt;삭제 쿼리를 쓰기 지연 SQL 저장소에 등록 ➡️ 커밋해서 플러시 호출 시 실제 데이터베이스에 삭제 쿼리 전달&lt;/li&gt;
&lt;li&gt;remove()를 호&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;출하는 순간 영속성 컨텍스트에서 제거&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;삭제된 엔티티는 재사용하지 말고 자연스럽게 가비지 컬렉션 대상이 되도록 두는 것이 좋음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/8</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-5#entry8comment</comments>
      <pubDate>Fri, 8 Nov 2024 21:21:01 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #4</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-4</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.1 이클립스 설치와 프로젝트 불러오기 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.2 H2 데이터베이스 설치 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.3 라이브러리와 프로젝트 구조 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.4 객체 매핑 시작 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.5 persistence.xml 설정 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.6 애플리케이션 개발 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2.7 정리 ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;이클립스 설치와 프로젝트 불러오기&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이클립스 설치: Eclipse IDE for Java EE Developers 패키지 권장, 자신에게 맞는 환경의 이클립스 설치&lt;/li&gt;
&lt;li&gt;  프로젝트: &lt;a title=&quot;jpabook&quot; href=&quot;https://github.com/holyeye/jpabook&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/holyeye/jpabook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1730985863958&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - holyeye/jpabook&quot; data-og-description=&quot;Contribute to holyeye/jpabook development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/holyeye/jpabook&quot; data-og-url=&quot;https://github.com/holyeye/jpabook&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6wepu/hyXs3MddZY/wwLYoal5HlCMoaQ2zd8U2K/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_140_1049_228,https://scrap.kakaocdn.net/dn/bhXGd5/hyXsZC3NQf/jDfkbgneKrDxZqPzhGsu0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_140_1049_228&quot;&gt;&lt;a href=&quot;https://github.com/holyeye/jpabook&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/holyeye/jpabook&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6wepu/hyXs3MddZY/wwLYoal5HlCMoaQ2zd8U2K/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_140_1049_228,https://scrap.kakaocdn.net/dn/bhXGd5/hyXsZC3NQf/jDfkbgneKrDxZqPzhGsu0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_140_1049_228');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - holyeye/jpabook&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to holyeye/jpabook development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt; H2 데이터베이스 설치&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;  링크: &lt;a title=&quot;http://www.h2database.com&quot; href=&quot;http://www.h2database.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.h2database.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;All Platforms 또는 Platform-Independent Zip 다운로드&lt;/li&gt;
&lt;li&gt;설정 정보
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;드라이버 클래스&lt;/b&gt;: org.h2.Driver&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JDBC URL&lt;/b&gt;: jdbc:h2:tcp://localhost/~/test&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자명&lt;/b&gt;: sa&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비밀번호&lt;/b&gt;: 입력하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리와 프로젝트 구조&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Maven&lt;/span&gt;을 사용하여 필요한 라이브러리 관리 ➡️ &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;pom.xml&lt;/span&gt;에 사용할 라이브러리를 적어주면 라이브러리를 자동으로 내려받아서 관리&lt;/li&gt;
&lt;li&gt;프로젝트 구조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;src/main
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;jpabook/start
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JpaMain.java (실행 클래스)&lt;/li&gt;
&lt;li&gt;Member.java (회원 엔티티)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;resources
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;META-INF
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;persistence.xml (JPA 설정 정보)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pom.xml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;객체 매핑 시작&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매핑 정보&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;회원 객체&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;회원 테이블&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;클래스와 테이블&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Member&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;MEMBER&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;기본 키&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;id&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;필드와 컬럼&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;username&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;NAME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;필드와 컬럼&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;age&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;AGE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1730986441389&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//회원 클래스에 JPA가 제공하는 매핑 어노테이션 추가
package jpabook.start;

import javax.persistence.*;

@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;
    
    //매핑 정보가 없는 필드
    pirvate Integer age;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;@Entity
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;클래스를 테이블과 매핑한다고 JPA에게 알려주는 역할&lt;/li&gt;
&lt;li&gt;엔티티 클래스라 칭함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Table
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;엔티티 클래스에 매핑할 테이블 정보 알려줌&lt;/li&gt;
&lt;li&gt;이 어노테이션을 생략하면 클래스 이름을 테이블 이름으로 매핑함 (더 정확히는 엔티티 이름을 사용함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Id
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&amp;nbsp;엔티티 클래스의 필드를 데이틀의 기본 키(PK)에 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;@Column
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&amp;nbsp;필드를 컬럼에 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;매핑 정보가 없는 필드
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;매핑 어노테이션을 생략하면 필드명을 사용해서 컬럼명으로 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;✅ JPA 어노테이션의 패키지는 javax.persistence 이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;persistence.xml 설정&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리&lt;/li&gt;
&lt;li&gt;이 설정 파일이 META-INF/persistence.xml 클래스 패스 경로에 있으면 별도의 설정 없이 JPA가 인식 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730986809445&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;&amp;gt;
&amp;lt;persistence xmlns=&quot;http://xmlns.jcp.org/xml/ns/persistence&quot;
	version=&quot;2.1&quot;&amp;gt;
    &amp;lt;persistence-unit name=&quot;jpabook&quot;&amp;gt;
    	&amp;lt;properties&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 유닛(persistence-unit): 일반적으로 연결할 데이터베이스당 하나의 영속성 유닛을 등록&lt;br /&gt;고유한 이름을 부여해야 하고, 여기서는&amp;nbsp; 'jpabook'이라는 이름 사용&lt;/li&gt;
&lt;li&gt;JPA 표준 속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;javax.persistence.jdbc.driver: JDBC 드라이버&lt;/li&gt;
&lt;li&gt;javax.persistence.jdbc.user: 데이터베이스 접속 아이디&lt;/li&gt;
&lt;li&gt;javax.persistence.jdbc.password: 데이터베이스 접속 비밀번호&lt;/li&gt;
&lt;li&gt;javax.persistence.jdbc.url: 데이터베이스 접속 URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하이버네이트 속성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;hibernate.dialect: 데이터베이스 방언 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;데이터베이스 방언&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 타입: 가변 문자 타입으로 MySQL은 VARCHAR, 오라클은 VARCHAR2를 사용&lt;/li&gt;
&lt;li&gt;다른 함수명: 문자열을 자르는 함수로 SQL 표준은 SUBSTRING()를 사용하지만 오라클은 SUBSTR() 사용&lt;/li&gt;
&lt;li&gt;페이징 처리: MySQL은 LIMIT를 사용하지만 오라클은 ROWNUM을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;애플리케이션 개발&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 매니저 팩토리 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA를 시작하기 위해, persistence.xml의 설정 정보를 사용해서 엔티티 매니저 팩토리 생성&lt;/li&gt;
&lt;li&gt;엔티티 매니저 팩토리는 애플리케이션 전체에서 딱 한 번만 생성하고 공유해서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;엔티티 매니저 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 매니저 팩토리에서 엔티티 매니저 생성&lt;/li&gt;
&lt;li&gt;JPA 기능의 대부분은 이 엔티티 매니저가 제공&lt;/li&gt;
&lt;li&gt;엔티티 매니저를 사용해서 엔티티를 데이터베이스에 CRUD 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;엔티티 매니저는 데이터베이스 커넥션과 밀접한 관계가 있으므로 스레드 간 공유하거나 재사용하면 안됨&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;종료
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔티티 매니저 종료: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;em.close();&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;엔티티 매니저 팩토리 종료: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;emf.close();&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA를 사용하려면 항상 트랜잭션 안에서 데이터 변경&lt;/li&gt;
&lt;li&gt;트랜젝션 없이 데이터를 변경하면 예외 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비즈니스 로직
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;등록: persist() 메소드에 저장할 엔티티 넘겨주기&lt;/li&gt;
&lt;li&gt;수정: 엔티티의 값 변경 ➡️ JPA는 어떤 엔티티가 변경되었는지 추적하는 기능을 갖추고 있음&lt;/li&gt;
&lt;li&gt;삭제: remove() 메소드에 삭제하려는 엔티티 넘겨주기&lt;/li&gt;
&lt;li&gt;한 건 조회: 조회할 엔티티 타입과 @Id로 데이터베이스 테이블의 기본 키와 매핑한 식별자 값으로 엔티티 하나를 조회&lt;/li&gt;
&lt;li&gt;JPQL: 필요한 데이터만 데이터베이스에서 불러오려면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;결국 검색조건이 포함된 SQL 사용&lt;/span&gt;해야 하는데 이때 JPQL 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPQL = Java Persistence Query Language
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;JPQL: &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;엔티티 객체를 대상&lt;/b&gt;&lt;/span&gt;으로 쿼리&lt;/li&gt;
&lt;li&gt;&amp;nbsp;SQL: &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;데이터베이스 테이블&lt;/b&gt;&lt;/span&gt;을 대상으로 쿼리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;select m from Member m
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;from Member는 회원 엔티티 객체를 말하는 것이지, Member 테이블이 아님&lt;/li&gt;
&lt;li&gt;JPQL은 데이터베이스 테이블을 전혀 알지 못함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JPQL은 대소문자를 명확하게 구분하지만, SQL은 관례상 대소문자를 구분하지 않고 사용하는 경우가 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/7</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-4#entry7comment</comments>
      <pubDate>Thu, 7 Nov 2024 22:53:22 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 자바 ORM 표준 JPA 프로그래밍 #3</title>
      <link>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-3</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;책 제목: 자바 ORM 표준 JPA 프로그래밍&lt;br /&gt;저&amp;nbsp; &amp;nbsp; 자: 김영한&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  목차&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장) JPA 소개&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 1.3 JPA란 무엇인가? ✅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2장) JPA 시작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3장) 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4장) 엔티티 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;5장) 연관관계 매핑 기초&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;6장) 다양한 연관관계 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;7장) 고급 매핑&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;8장) 프록시와 연관관계 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;9장) 값 타입&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;10장) 객체지향 쿼리 언어&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;11장) 웹 애플리케이션 제작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;12장) 스프링 데이터 JPA&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;13장) 웹 애플리케이션과 영속성 관리&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;14장) 컬렉션과 부가 기능&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;15장) 고급 주제와 성능 최적화&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;16장 트랜잭션과 락, 2차 캐시&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;JPA란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA(Java Persistence API)란, 자바 진영의 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;ORM&lt;/span&gt;&lt;/b&gt; 기술 표준&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션과 JDBC 사이에서 동작&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0117.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byNv9g/btsKyG4hrFp/uKoe9I0tmqdZzOuE4b0BSK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byNv9g/btsKyG4hrFp/uKoe9I0tmqdZzOuE4b0BSK/img.jpg&quot; data-alt=&quot;[사진1] JPA 위치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byNv9g/btsKyG4hrFp/uKoe9I0tmqdZzOuE4b0BSK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyNv9g%2FbtsKyG4hrFp%2FuKoe9I0tmqdZzOuE4b0BSK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;2393&quot; data-filename=&quot;IMG_0117.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;2393&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[사진1] JPA 위치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM(Object-Relational Mapping)은 &lt;b&gt;객체와 관계형 데이터베이스를 매핑&lt;/b&gt;한다는 뜻.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM 프레임워크는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결&lt;/span&gt;해줌.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0118.jpg&quot; data-origin-width=&quot;3521&quot; data-origin-height=&quot;2690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/do6bsm/btsKyDsQh1U/7kC6M7kq19G8ViIYNVICek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/do6bsm/btsKyDsQh1U/7kC6M7kq19G8ViIYNVICek/img.jpg&quot; data-alt=&quot;[사진2] JPA를 사용하여 INSERT 구현 시 로직&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/do6bsm/btsKyDsQh1U/7kC6M7kq19G8ViIYNVICek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdo6bsm%2FbtsKyDsQh1U%2F7kC6M7kq19G8ViIYNVICek%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3521&quot; height=&quot;2690&quot; data-filename=&quot;IMG_0118.jpg&quot; data-origin-width=&quot;3521&quot; data-origin-height=&quot;2690&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[사진2] JPA를 사용하여 INSERT 구현 시 로직&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 측면에서는 정교한 객체 모델링 가능&lt;/li&gt;
&lt;li&gt;관계형 데이터베이스는 데이터베이스에 맞도록 모델링만 하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 객체와 관계형 데이터베이스를 어떻게 매핑해야 하는지 매핑 방법만 ORM 프레임워크에 알려주면 됨&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt; ORM 종류&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;어느 정도 성숙한 객체지향 언어에는 대부분 ORM 프레임워크들의 있는데 각 프레임워크의 성숙도에 따라 단순 CRUD 기능만 제공하는 것부터 패러다임 불일치 문제를 대부분 해결해주는 ORM 프레임워크도 존재&lt;/li&gt;
&lt;li&gt;자바 진영에서는 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;하이버네이트 프레임워크&lt;/b&gt;&lt;/span&gt;를 가장 많이 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;JPA 소개&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔터프라이즈 자바 빈즈(EJB) 3.0에서 하이버네이트를 기반으로 새로운 자바 ORM 기술 표준이 만들어졌는데 이것이 바로 JPA다.&lt;/li&gt;
&lt;li&gt;JPA는 &lt;b&gt;자바 ORM 기술에 대한 API 표준 명세&lt;/b&gt;, 즉 인터페이스를 모아놓은 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_0120.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;1735&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NwXNZ/btsKzmYlHZB/5QjsJnMEVM3vJBdQozt8dk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NwXNZ/btsKzmYlHZB/5QjsJnMEVM3vJBdQozt8dk/img.jpg&quot; data-alt=&quot;[사진3] JPA 표준 인터페이스와 구현체&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NwXNZ/btsKzmYlHZB/5QjsJnMEVM3vJBdQozt8dk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNwXNZ%2FbtsKzmYlHZB%2F5QjsJnMEVM3vJBdQozt8dk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4030&quot; height=&quot;1735&quot; data-filename=&quot;IMG_0120.jpg&quot; data-origin-width=&quot;4030&quot; data-origin-height=&quot;1735&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[사진3] JPA 표준 인터페이스와 구현체&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 교재에서는 JPA 2.1 버전의 구현 프레임워크로 하이버네이트 사용&lt;/li&gt;
&lt;li&gt;JPA 버전별 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA 1.0(JSR 220) 2006년: 초기버전. 복합 키와 연관관계 기능 부족&lt;/li&gt;
&lt;li&gt;JPA 2.0(JSR 317) 2009년: 대부분의 ORM 기능을 포함하고 JPA Criteria가 추가됨&lt;/li&gt;
&lt;li&gt;JPA 2.1(JSR 338) 2013년: 스토어드 프로시저 접근, 컨버터(Converter), 엔티티 그래프 기능 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;JPA 를 사용해야 하는 이유&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;생산성&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SQL과 JDBC API 사용을 반복적으로 개발자가 직접 작성하지 않아도 됨&lt;/li&gt;
&lt;li&gt;DDL문을 자동 생성 기능 존재&lt;/li&gt;
&lt;li&gt;데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 역전 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;유지보수&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JPA가 JDBC API 코드 변경과 같은 일을 대신 처리해주므로 필드를 추가하거나 삭제해도 수정해야 할 코드가 줄어듦&lt;/li&gt;
&lt;li&gt;유지보수해야 하는 코드의 수가 줄어듦&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;패러다임 불일치 해결&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;성능&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션과 데이터베이스 사이에서 다양한 성능 최적화 기회 제공&lt;/li&gt;
&lt;li&gt;같은 트랜잭션 안에서 같은 회원을 두 번 조회하는 코드의 일부분이 다음과 같을 때,&lt;br /&gt;JPA를 사용하면 &lt;u&gt;회원을 조회하는 SELECT SQL을 한 번만 데이터베이스에 전달&lt;/u&gt;하고 두 번째는 &lt;u&gt;조회한 회원 객체 재사용&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1730900666723&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String memberId = &quot;helloId&quot;;
Member member1 = jpa.find(memberId);
Member member2 = jpa.find(memberId);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;데이터 접근 추상화와 벤더 독립성&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다름&lt;/li&gt;
&lt;li&gt;JPA는 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 함&lt;/li&gt;
&lt;li&gt;데이터베이스 변경 시 JPA에게 다른 데이터베이스를 사용한다고 알려주기만 하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  QnA&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;✋ ORM 프레임워크를 사용하면 SQL과 데이터베이스는 잘 몰라도 괜찮은가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt; ️ ORM 프레임워크를 사용할 때 가장 중요한 일은 객체와 테이블을 매핑하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;매핑을 올바르게 하기 위해서는 객체와 관계형 데이터베이스 양쪽을 모두 이해해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;✋ 통계 쿼리처럼 매우 복잡한 SQL은 어떻게 하나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt; ️ JPA는 통계 쿼리 같이 복잡한 쿼리보다는 실시간 처리용 쿼리에 더 최적화 되어 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JPA가 제공하는 네이티브 SQL을 사용하거나, 마이바티스나 스프링의 JdbcTemplate 같은 SQL 매퍼 형태의 프레임워크 혼용하는 것도 좋은 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;✋ 학습곡선이 높다고 하던데?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt; ️ JPA를 사용하려면 객체와 관계형 데이터베이스를 어떻게 매핑하는지 학습한 후에 JPA의 핵심 개념들을 이해해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JPA가 어려운 근본적인 이유는 ORM이 객체지향과 관계형 데이터베이스의 두 기둥 위에 있기 때문임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 둘의 기초가 부족하면 어려울 수 밖에 없음.&lt;/p&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Book</category>
      <category>Java</category>
      <category>JPA</category>
      <category>spring</category>
      <category>study</category>
      <category>women in spring</category>
      <category>김영한</category>
      <author>지니(jineey)</author>
      <guid isPermaLink="true">https://jineey-dev.tistory.com/6</guid>
      <comments>https://jineey-dev.tistory.com/entry/JPA-%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-3#entry6comment</comments>
      <pubDate>Wed, 6 Nov 2024 22:50:45 +0900</pubDate>
    </item>
  </channel>
</rss>