JavaRush /Java Blog /Random-KO /JPA 엔터티 및 DB 관계
Nikita Koliadin
레벨 40
Днепр

JPA 엔터티 및 DB 관계

Random-KO 그룹에 게시되었습니다

JPA 엔터티 및 DB 관계

좋은 하루 되세요, 동료 여러분!
JPA 엔터티 및 DB 관계 - 1
이 자료는 데이터베이스(이하 간단히 DB - "데이터베이스") 구성, 객체 관계형 매핑(이하 간단히 ORM ) 작동 방식에 대한 최소한의 지식, Hibernate/JPA 와 같은 구현 에 대해 이미 이해하고 있는 사람들을 대상으로 합니다. . 이에 익숙하지 않다면 JDBC 로 시작한 다음 ORM 모델로 넘어가는 것이 좋습니다. 나는 당신에게 경고했고, 적절한 준비 없이 이 글을 읽은 당신의 정신에 대해 나는 책임을 지지 않습니다! :) 모든 것을 순서대로 다루기 시작하겠습니다. 먼저, 우리는 이론을 조금만 파헤쳐 보겠습니다. 둘째, 모두가 좋아하는 Java에서 이 작업을 수행하는 방법을 알아 보겠습니다. 또한 주제에 대한 이해를 통합하고 매핑을 수행하는 방법 에 대한 템플릿 역할을 하는 프로젝트 치트 시트를 작성해 드릴 것입니다 . 그럼 해보자!

엔터티란 무엇입니까?

엔터티 는 속성(문, WHEELS , 엔진) 을 가진 실생활의 객체(예: 자동차) 입니다 . DB 엔터티: 이 경우 엔터티는 DB에 저장되므로 모든 것이 간단합니다. 자동차를 데이터베이스에 저장하는 이유와 방법은 나중에 살펴보겠습니다.

DB 관계란 무엇입니까?

먼 옛날, 먼 왕국에서는 관계형 DB가 만들어졌습니다 . 본 DB에서는 데이터를 테이블 형태로 표현하였다. 그러나 Shrek의 당나귀에게는 이러한 테이블을 상호 연결하기 위한 메커니즘을 만드는 것이 필요하다는 것도 분명했습니다. 그 결과 4개의 DB 관계가 나타났습니다 .
  1. 1-1
  2. 일대다
  3. 다대일
  4. 다대다
이 모든 것을 처음으로 본다면 다시 한 번 경고합니다. 상황이 더 악화될 것입니다. 산책하러 가는 것을 생각해 보세요. 우리는 예제를 사용하여 이러한 모든 관계를 분석하고 이들 간의 차이점을 이해합니다.

공포의 예

우리는 프로젝트에 대한 설명이 있는 마스터와 각 DB 관계에 대한 1개의 브랜치, 즉 5개의 브랜치를 갖는 하나의 프로젝트를 갖게 됩니다. 각 분기에는 DB를 생성하고 테스트 데이터로 채우는 SQL 스크립트와 주석 매핑이 있는 Entity 클래스가 포함됩니다. 각 브랜치에 대한 Hibernate 구성 파일도 있을 것입니다. 프로젝트에서는 클라우드 DB나 외부 DB의 개별적인 부분에 방해가 되지 않도록 H2 임베디드 DB를 활용하겠습니다 . 링크를 따라가시면 진공청소기에 H2 DB를 설치하실 수 있습니다. 1개 분기의 각 단계를 설명하고 나머지는 핵심 사항일 뿐입니다. 마지막으로 요약하겠습니다. 가다. 이것은 내 프로젝트의 마스터 브랜치에 대한 링크입니다.

일대일 관계

여기 에 지점 링크를 걸어주세요 .
  1. 우리 프로젝트에 H2 DB를 연결해야 합니다. 여기서는 DB 등을 편하게 다루기 위해서는 Ultimate IDEA가 필요하다는 점을 강조하고 싶습니다. 이미 가지고 있다면 DB 연결로 바로 이동하세요. 데이터베이스 탭으로 이동하여 스크린샷과 같이 수행합니다.

    JPA Entities and DB Relationships - 2

    다음으로 DB 설정으로 넘어갑니다. 데이터는 물론 DBMS까지 입력할 수 있습니다. 반복하지만 단순화를 위해 H2 DB를 사용합니다.

    JPA Entities and DB Relationships - 3

    다음으로 회로를 구성해 보겠습니다. 이 단계는 선택 사항이지만 DB에 여러 스키마가 있는 경우 권장됩니다.

    JPA Entities and DB Relationships - 4

    설정을 적용하면 결국 다음과 같은 결과를 얻게 됩니다.

    JPA Entities and DB Relationships - 5
  2. 우리는 데이터베이스를 생성하고 IDEA에서 이에 대한 액세스를 구성했습니다. 이제 그 안에 테이블을 만들고 일부 데이터로 채워야 합니다. 예를 들어 Author와 Book이라는 두 엔터티를 사용하겠습니다. 책에는 저자가 있을 수도 있고, 여러 명의 저자가 있을 수도 있고, 없을 수도 있습니다. 이 예에서는 모든 유형의 연결을 생성합니다. 하지만 이 시점에서는 - 일대일 관계입니다. DB 테이블을 생성하는 해당 스크립트를 만들어 보겠습니다 .

    DROP TABLE IF EXISTS PUBLIC.BOOK;
    
    CREATE TABLE PUBLIC.BOOK (
      ID         INTEGER      NOT NULL AUTO_INCREMENT,
      NAME       VARCHAR(255) NOT NULL,
      PRINT_YEAR INTEGER(4)   NOT NULL,
      CONSTRAINT BOOK_PRIMARY_KEY PRIMARY KEY (ID)
    );
    
    DROP TABLE IF EXISTS PUBLIC.AUTHOR;
    
    CREATE TABLE PUBLIC.AUTHOR (
      ID          INTEGER      NOT NULL AUTO_INCREMENT,
      FIRST_NAME  VARCHAR(255) NOT NULL,
      SECOND_NAME VARCHAR(255) NOT NULL,
      BOOK_ID     INTEGER      NOT NULL UNIQUE,
      CONSTRAINT AUTHOR_PRIMARY_KEY PRIMARY KEY (ID),
      CONSTRAINT BOOK_FOREIGN_KEY FOREIGN KEY (BOOK_ID) REFERENCES BOOK (ID)
    );

    그리고 그것을 실행해 봅시다:

    JPA Entities and DB Relationships - 6

    콘솔의 실행 결과:

    JPA Entities and DB Relationships - 7

    DB 결과:

    JPA Entities and DB Relationships - 8
  3. 테이블 다이어그램을 살펴보겠습니다. 이렇게 하려면 DB에서 RMB를 사용하세요.

    JPA Entities and DB Relationships - 9

    결과:

    JPA Entities and DB Relationships - 10

    UML 다이어그램 에서는 모든 기본 키와 외래 키를 볼 수 있으며 테이블 간의 연결도 볼 수 있습니다.

  4. 테스트 데이터로 DB를 채우는 스크립트를 작성해 보겠습니다 .

    INSERT INTO PUBLIC.BOOK (NAME, PRINT_YEAR)
    VALUES ('First book', 2010),
           ('Second book', 2011),
           ('Third book', 2012);
    
    INSERT INTO PUBLIC.AUTHOR (FIRST_NAME, SECOND_NAME, BOOK_ID)
    VALUES ('Pablo', 'Lambado', 1),
           ('Pazo', 'Zopa', 2),
           ('Lika', 'Vika', 3);

    내 말은, 무슨 일이 일어나는 거죠? 한 테이블의 엔터티가 다른 엔터티와 관련되어 있는 경우(또는 BOOK_ID에서 NOT NULL이 제거된 경우 전혀 관련되지 않은 경우) 일대일 관계가 필요합니다. 이 예에서는 한 권의 책에 저자가 한 명 있어야 합니다. 다른 방법은 없습니다.

  5. 이제 가장 흥미로운 점은 Java 클래스를 DB 엔터티와 연결하는 방법입니다. 매우 간단합니다. Book과 Author라는 두 개의 클래스를 만들어 보겠습니다. 예시를 통해 클래스1과 주요 커뮤니케이션 분야를 분석해보겠습니다. Author 클래스를 예로 들어보겠습니다 .

    @Data
    @Entity
    @DynamicInsert
    @DynamicUpdate
    @Table(name = "AUTHOR")
    public class Author {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID", nullable = false)
        private Long id;
    
        @Column(name = "FIRST_NAME", nullable = false)
        private String firstName;
    
        @Column(name = "SECOND_NAME", nullable = false)
        private String secondName;
    
        @OneToOne
        @JoinColumn(name = "BOOK_ID", unique = true, nullable = false)
        private Book book;
    }
순서대로 알아 봅시다.
  1. 클래스의 모든 필드는 DB 엔터티의 속성을 반복합니다.
  2. @Data (from Lombok )는 각 필드에 대해 getter 및 setter가 생성되고, 해시코드가 재정의되고, toString 메서드가 생성될 것이라고 말합니다.
  3. @Entity는 주어진 클래스가 엔터티이고 DB 엔터티와 연결되어 있음을 나타냅니다.
  4. @DynamicInsert@DynamicUpdate는 동적 삽입 및 업데이트가 DB에서 수행된다고 말합니다. 이것은 올바른 일괄 처리를 수행하는 데 도움이 될 더 깊은 Hibernate 설정입니다.
  5. @Table (name = "AUTHOR")은 Book 클래스를 DB AUTHOR 테이블에 바인딩합니다.
  6. @Id는 이 필드가 기본 키라고 말합니다.
  7. @GeneratedValue (strategy = GenerationType.IDENTITY) – 기본 키 생성 전략입니다.
  8. @Column (name = "ID", nullable = false)은 필드를 DB 속성과 연결하고 지정된 DB 필드가 null일 수 없음을 나타냅니다. 이는 엔터티에서 테이블을 생성할 때도 유용합니다. 지금 프로젝트를 생성하는 방법의 반대 프로세스는 단위 테스트를 위한 테스트 DB에 필요합니다.
  9. @OneToOne은 주어진 필드가 일대일 관계 필드임을 나타냅니다.
  10. @JoinColumn (name = "BOOK_ID", Unique = true, nullable = false) - null이 아닌 고유한 BOOK_ID 열이 생성됩니다.
반대쪽( Book 클래스 )에서도 일대일 연결을 만들고 매핑이 발생하는 필드를 표시해야 합니다. @OneToOne(mappedBy = "book") - 이 예에서는 Author 클래스의 book 필드입니다. JPA는 이를 자체적으로 연결합니다. 언뜻 보면 주석이 엉망인 것처럼 보일 수도 있지만 실제로는 매우 편리하고 경험이 쌓이면 생각하지 않고도 자동으로 추가할 수 있습니다.
  1. 이제 최대 절전 모드를 구성해 보겠습니다. 이를 수행하려면 hibernate.cfg.xml 파일을 생성하십시오:

    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
            <property name="hibernate.connection.driver_class">org.h2.Driver</property>
    
            <property name="hibernate.connection.url">jdbc:h2:~/db/onetoone</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password"/>
    
            <property name="hibernate.hbm2ddl.auto">update</property>
    
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>
            <property name="hibernate.use_sql_comments">true</property>
    
            <property name="hibernate.generate_statistics">true</property>
    
            <property name="hibernate.jdbc.batch_size">50</property>
            <property name="hibernate.jdbc.fetch_size">50</property>
    
            <property name="hibernate.order_inserts">true</property>
            <property name="hibernate.order_updates">true</property>
            <property name="hibernate.jdbc.batch_versioned_data">true</property>
    
            <mapping class="com.qthegamep.forjavarushpublication2.entity.Book"/>
            <mapping class="com.qthegamep.forjavarushpublication2.entity.Author"/>
        </session-factory>
    </hibernate-configuration>
속성 설명 :
  1. hibernate.dialect는 우리가 선택한 DBMS의 방언입니다.
  2. hibernate.connection.driver_class - DB의 드라이버 클래스입니다.
  3. hibernate.connection.url - 우리 DB의 utl. DB를 처음 구성한 시점부터 가져오실 수 있습니다.
  4. hibernate.connection.username - DB 사용자 이름.
  5. hibernate.connection.password — DB 사용자 비밀번호.
  6. hibernate.hbm2ddl.auto - 테이블 생성 설정. 업데이트하는 경우 이미 생성된 경우 생성되지 않고 업데이트만 됩니다.
  7. hibernate.show_sql - DB 쿼리 표시 여부.
  8. hibernate.format_sql - DB 쿼리 포맷 여부. 그렇지 않으면 모두 한 줄에 있게 됩니다. 켜는 것이 좋습니다.
  9. hibernate.use_sql_comments - DB 쿼리에 주석을 달았습니다. 삽입인 경우 해당 요청이 삽입 유형이라는 설명이 요청 위에 기록됩니다.
  10. hibernate.generate_statistics - 로그를 생성합니다. 로깅을 최대로 설정하는 것이 좋습니다. 로그를 읽으면 ORM을 올바르게 사용할 가능성이 높아집니다.
  11. hibernate.jdbc.batch_size — 최대 배치 크기.
  12. hibernate.jdbc.fetch_size — 최대 가져오기 크기.
  13. hibernate.order_inserts - 동적 삽입을 허용합니다.
  14. hibernate.order_updates - 동적 업데이트를 허용합니다.
  15. hibernate.jdbc.batch_versioned_data - 일괄 처리를 허용합니다. DBMS를 살펴보세요. 모든 사람이 이를 지원하는 것은 아닙니다.
  16. 매핑 클래스 - 엔터티인 클래스입니다. 모든 것을 나열해야합니다.
  1. 이제 우리의 본질이 결정되어야 합니다. 지속성 탭에서 이를 확인할 수 있습니다.

    JPA Entities and DB Relationships - 11

    결과:

    JPA Entities and DB Relationships - 12
  2. 또한 할당 데이터를 구성해야 합니다.

    JPA Entities and DB Relationships - 13 JPA Entities and DB Relationships - 14

    결과: 일대일 매핑을 수행했습니다. 본 자료는 참고용으로만 제공되며 자세한 내용은 참고자료에 나와 있습니다.

일대다 관계

여기 에 지점 링크를 걸어주세요 . 이미 너무 길기 때문에 더 이상 기사에 코드를 게시하지 않겠습니다. 우리는 GitHub의 모든 코드를 살펴봅니다.
  1. 초기화 스크립트를 실행한 결과 다음을 얻습니다.

    JPA Entities and DB Relationships - 15

    앞의 표와 차이점이 느껴지시나요?

  2. 도표:

    JPA Entities and DB Relationships - 16

    일대다 관계 - 한 명의 저자가 여러 권의 책을 가질 수 있습니다. 왼쪽 엔터티는 하나 이상의 오른쪽 엔터티에 해당합니다.

  3. 매핑의 차이점은 주석과 필드에 있습니다.

    Author 클래스 에 필드가 나타납니다 .

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
    private Set<Book> books;

    여러 권의 책을 가질 수 있으므로 이미 세트입니다. @OneToMany 는 관계 유형에 대해 이야기하고 있습니다. FetchType.Lazy는 요청에 지정되지 않은 경우 전체 도서 목록을 로드할 필요가 없다고 말합니다. 또한 이 필드는 toString에 추가할 수 없습니다. 그렇지 않으면 StackOverflowError가 발생하기 시작합니다. 나의 사랑하는 Lombok은 이것을 처리합니다:

    @ToString(exclude = "books")

    Book 클래스 에서는 다대일 피드백을 수행합니다.

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "AUTHOR_ID", nullable = false)
    private Author author;

    여기서 우리는 일대다(One-to-Many)가 다대일(Many-to-One)의 거울 이미지이고 그 반대의 경우도 마찬가지라는 결론을 내립니다. Hibernate는 양방향 통신에 대해 아무것도 모른다는 점을 강조해야 합니다. 그에게 이것은 두 가지 다른 연결입니다. 하나는 한 방향이고 다른 하나는 반대 방향입니다.

  4. hibernate.cfg.xml 에는 크게 변경된 사항이 없습니다 .

  5. 고집:

    JPA Entities and DB Relationships - 17

다대일 관계

다대일은 일대다의 미러 이미지이므로 차이가 거의 없습니다. 여기 에 지점 링크를 걸어주세요 .
  1. 초기화 스크립트를 실행한 결과 다음과 같은 결과를 얻습니다.

    JPA Entities and DB Relationships - 18
  2. 도표:

    JPA Entities and DB Relationships - 19
  3. 매핑의 차이점은 주석과 필드에 있습니다.

    Author 클래스 에는 Book 클래스 로 이동되었으므로 더 이상 세트가 없습니다 .

  4. hibernate.cfg.xml

  5. 고집:

    JPA Entities and DB Relationships - 20

다대다 관계

가장 흥미로운 관계로 넘어가겠습니다. 품위와 외설의 모든 규칙에 따라 이 관계는 추가 테이블을 통해 생성됩니다. 하지만 이 테이블은 엔터티가 아닙니다. 흥미롭지 않나요? 이 똥을 살펴 보겠습니다. 여기 에 지점 링크를 걸어주세요 .
  1. 초기화 스크립트를 보면 여기에 추가 HAS 테이블이 나타납니다. 우리는 저자가 책을 가지고 있는 것과 같은 것을 얻습니다.

    스크립트를 실행한 결과 다음 테이블이 표시됩니다.

    JPA Entities and DB Relationships - 21
  2. 도표:

    JPA Entities and DB Relationships - 22

    우리의 예에서는 한 책에 여러 명의 저자가 있을 수 있고, 한 저자에 여러 권의 책이 있을 수 있다는 사실이 밝혀졌습니다. 겹칠 수도 있습니다.

  3. 매핑 클래스에는 클래스 내에 세트가 있습니다. 하지만 앞서 말했듯이 HAS 테이블은 엔터티가 아닙니다.

    저자 클래스 :

    @ManyToMany
    @JoinTable(name = "HAS",
            joinColumns = @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID"),
            inverseJoinColumns = @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")
    )
    private Set<Book> books;

    @ManyToMany 는 일종의 관계입니다.

    @JoinTable - 이는 정확히 속성을 추가 HAS 테이블과 연결하는 것입니다. 여기에는 두 엔터티의 기본 키를 가리키는 두 가지 속성을 지정합니다.

    도서 수업 :

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "books")
    private Set<Author> authors;

    여기서는 FetchType과 매핑에 사용할 필드를 나타냅니다.

  4. hibernate.cfg.xml 은 다시 변경되지 않은 상태로 유지되었습니다(각 지점에 대해 새 DB를 생성했다는 사실은 고려하지 않았습니다).

  5. 고집:

    JPA Entities and DB Relationships - 23

복명

그래서 우리는 DB 관계의 유형을 표면적으로 살펴보고 이를 ORM 모델에서 구현하는 방법을 알아냈습니다. 우리는 모든 연결을 보여주는 테스트 프로젝트를 작성하고 hibernate/jpa를 구성하는 방법을 알아냈습니다. 휴.

유용한 링크

내 이전 기사: PS 본문에 오류나 부족한 부분이 있을 수 있습니다. PPS 저자는 이 글을 쓰면서 이상한 담배를 피우고 있었습니다. 관심을 가져주셔서 감사합니다!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION