반응형

📖 연관관계 매핑 종류와 방향

연관관계를 맺는 두 엔티티 간에 생성할 수 있는 연관관계의 종류는 아래와 같습니다.

  • One To One : 일 대 일(1:1)
  • One To Many : 일 대 다(1:N)
  • Many To One : 다 대 일(N:1)
  • Many To Many : 다 대 다(N:M)

데이터베이스에서는 두 테이블의 연관관계를 설정하면 외래키(FK)를 통해 서로 조인해서 참조하는 구조로 생성되지만,

JPA를 사용하는 객체지향 모델링에서는 엔티티 간 참조 방향을 설정할 수 있습니다.

데이터베이스와 관계를 일치시키기 위해 양방향으로 설정해도 무관하지만, 비즈니스 로직 관점에서 봤을 때는 단방향 관계만 설정해도 해결되는 경우가 많습니다. 단방향과 양방향 관계에 대해 아래에 간단하게 정리하면 다음과 같습니다.

  • 단방향 : 두 엔티티의 관계에서 한쪽의 엔티티만 참조하는 형식
  • 양방향 : 두 엔티티의 관계에서 각 엔티티가 서로의 엔티티를 참조하는 형식

연관관계가 설정되면 한 테이블에서 다른 테이블의 기본값을 외래키로 갖게 됩니다.

이런 관계에서는 주인(Owner)이라는 개념이 사용됩니다. 일반적으로 외래키를 가진 테이블이 그 관계의 주인이 되며, 주인은 외래키를 사용할 수 있으나 상대 엔티티는 읽는 작업만 수행할 수 있습니다.

 

이전 예제에서 부서(Department)와 사원(Employee) 테이블의 관계는 1:N(일대다) 관계이며 예제에서는 일 대 다 관계에 대해 설명하겠습니다.

 

JPA에서 테이블간 조인을 할 경우 어노테이션을 이용하여 조인을 합니다.

*         JPA 조인 : @(어노테이션)을 이용해서 조인함
*         부모(부서)-자식(사원) 관계
*                            1) 1:N - @OneToMany(부서), @ManytoOne(사원)
*                            2) 1:1 - @OneToOne(핸드폰), @OneToOne(사람)
*                            3) N:M - @ManyToMany (x)
 *             추천 : 1) 1 : N  : @OneToMany(부서), @ManyToOne(사원)
 *                       => 양방향 조인(불가피할 때 사용 -> 사용시 여러가지 문제 발생)
 *                 1-1) : 부서쪽에는 어노테이션 x, 사원에는 @ManyToOne 사용
 *                       => 단방향 조인(추천)

📖 일대다, 다대일 매핑

부서 테이블과 사원 테이블은 부서 테이블의 입장에서는 일대다(하나의 부서에는 여러명의 사원 존재), 사원 테이블의 입장에서는 다대일 관계(사원은 하나의 부서에만 존재할 수 있음)로 볼 수 있습니다.

이러한 관계는 어떻게 구현해야 할지 직접 매핑하면서 알아보겠습니다 :)

 

📂 Employee.java

package com.example.jpacustomexam.model.exam04;

import com.example.jpacustomexam.model.BaseTimeEntity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

@Entity
@Table(name = "TB_EMPLOYEE")
@SequenceGenerator(
        name = "SQ_EMPLOYEE_GENERATOR"
        , sequenceName = "SQ_EMPLOYEE"
        , initialValue = 1
        , allocationSize = 1
)
@Setter
@Getter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
public class Employee extends BaseTimeEntity {
    //    @Id : Primary Key 에 해당
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "SQ_EMPLOYEE_GENERATOR"
    )
    @Column(columnDefinition = "NUMBER")
    private Integer eno;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String ename;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String job;

    @Column(columnDefinition = "NUMBER")
    private Integer manager;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String hiredate;

    @Column(columnDefinition = "NUMBER")
    private Integer salary;

    @Column(columnDefinition = "NUMBER")
    private Integer commission;

//    @Column(columnDefinition = "NUMBER")
//    private Integer dno; // 공통 컬럼(생략, 자동으로 생성해줌)
//    단방향 조인
//    사용법 : @JoinColumn(name = "조인컬럼명")
//    양방향 조인 시 : N + 1 문제 발생
//                1) 즉시 로딩(EAGER) : 기본 설정 -> 지연 로딩(LAZY)
//                                     (fetch = FetchType.LAZY)
//                      optional = false -> 조인방법(inner, outerjoin)
    @ManyToOne
    @JoinColumn(name = "dno")
    private Department department;


}

 

우선 사원테이블에 단방향 조인을 설정합니다.

사용법은 @ManyToOne 어노테이션을 작성합니다.

그리고 조인할 컬럼을 설정해야하는데 @JoinColumn 어노테이션을 사용합니다. 예제에서는 dno(부서번호)가 외래키로 지정되어 있으므로 @JoinColumn(name = "dno")로 설정하였습니다.

 

📂 DepartmentRepository.java

DepartmentRepository 인터페이스를 새로 생성합니다.

package com.example.jpacustomexam.repository.exam04;

import com.example.jpacustomexam.model.exam04.Department;
import com.example.jpacustomexam.model.exam04.Employee;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/**
 * packageName : com.example.jpacustomexam.repository.exam04
 * fileName : DepartmentRepository
 * author : GGG
 * date : 2023-10-19
 * description : 부서 레포지토리 (CRUD)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-19         GGG          최초 생성
 */
@Repository
public interface DepartmentRepository extends JpaRepository<Department, Integer> {
    @Query(value = "select e from Employee e inner join e.department d ")
    Page<Employee> selectJoinPage2(Pageable pageable);
}

객체쿼리를 사용하여 쿼리문을 작성합니다

 

📂 DepartmentService.java

DepartmentService 파일을 새로생성합니다.

package com.example.jpacustomexam.service.exam04;

import com.example.jpacustomexam.model.exam04.Employee;
import com.example.jpacustomexam.repository.exam04.DepartmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class DepartmentService {
    @Autowired
    DepartmentRepository departmentRepository;

//    단방향 조인 예제
    public Page<Employee> selectJoinPage2(Pageable pageable){
        Page<Employee> page = departmentRepository.selectJoinPage2(pageable);
        return page;
    }
}

📂 DepartmentController.java

 DepartmentController 파일을 새로 생성합니다.

package com.example.jpacustomexam.controller.exam04;

import com.example.jpacustomexam.dto.DeptEmpDto;
import com.example.jpacustomexam.model.exam04.Employee;
import com.example.jpacustomexam.service.exam04.DepartmentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/exam04")
public class DepartmentController {
    @Autowired
    DepartmentService departmentService;

   /** 단방향 조인 예제 */
    @GetMapping("/dept/join/paging2")
    public ResponseEntity<Object> selectJoinPage2(Pageable pageable) {
        try {
            Page<Employee> page
                    = departmentService.selectJoinPage2(pageable);
//          todo : Map 자료구조 정보 저장 : 1) 부서 객체, 2) 페이징 정보 (3개)
            Map<String, Object> response = new HashMap<>();
            response.put("emp", page.getContent());                         // 사원 객체
            response.put("currentPage", page.getNumber());                  // 현재페이지 번호
            response.put("totalItems", page.getTotalElements());            // 전체 테이블 건수
            response.put("totalPage", page.getTotalPages());                // 전체페이지 수

            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(response, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

📌 실행결과

더보기
GET http://localhost:8000/exam04/dept/join/paging2

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 19 Oct 2023 01:37:45 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
  "totalItems": 14,
  "totalPage": 1,
  "emp": [
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7369,
      "ename": "SMITH",
      "job": "CLERK",
      "manager": 7902,
      "hiredate": "1980-12-17 00:00:00",
      "salary": 800,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 20,
        "dname": "RESEARCH",
        "loc": "DALLAS"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7499,
      "ename": "ALLEN",
      "job": "SALESMAN",
      "manager": 7698,
      "hiredate": "1981-02-20 00:00:00",
      "salary": 1600,
      "commission": 300,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7521,
      "ename": "WARD",
      "job": "SALESMAN",
      "manager": 7698,
      "hiredate": "1981-02-22 00:00:00",
      "salary": 1250,
      "commission": 500,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7566,
      "ename": "JONES",
      "job": "MANAGER",
      "manager": 7839,
      "hiredate": "1981-04-02 00:00:00",
      "salary": 2975,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 20,
        "dname": "RESEARCH",
        "loc": "DALLAS"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7654,
      "ename": "MARTIN",
      "job": "SALESMAN",
      "manager": 7698,
      "hiredate": "1981-09-28 00:00:00",
      "salary": 1250,
      "commission": 1400,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7698,
      "ename": "BLAKE",
      "job": "MANAGER",
      "manager": 7839,
      "hiredate": "1981-05-01 00:00:00",
      "salary": 2850,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7782,
      "ename": "CLARK",
      "job": "MANAGER",
      "manager": 7839,
      "hiredate": "1981-06-09 00:00:00",
      "salary": 2450,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 10,
        "dname": "ACCOUNTING",
        "loc": "NEW YORK"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7788,
      "ename": "SCOTT",
      "job": "ANALYST",
      "manager": 7566,
      "hiredate": "1987-07-13 00:00:00",
      "salary": 3000,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 20,
        "dname": "RESEARCH",
        "loc": "DALLAS"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7839,
      "ename": "KING",
      "job": "PRESIDENT",
      "manager": null,
      "hiredate": "1981-11-17 00:00:00",
      "salary": 5000,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 10,
        "dname": "ACCOUNTING",
        "loc": "NEW YORK"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7844,
      "ename": "TURNER",
      "job": "SALESMAN",
      "manager": 7698,
      "hiredate": "1981-09-08 00:00:00",
      "salary": 1500,
      "commission": 0,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7876,
      "ename": "ADAMS",
      "job": "CLERK",
      "manager": 7788,
      "hiredate": "1987-07-13 00:00:00",
      "salary": 1100,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 20,
        "dname": "RESEARCH",
        "loc": "DALLAS"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7900,
      "ename": "JAMES",
      "job": "CLERK",
      "manager": 7698,
      "hiredate": "1981-12-03 00:00:00",
      "salary": 950,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 30,
        "dname": "SALES",
        "loc": "CHICAGO"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7902,
      "ename": "FORD",
      "job": "ANALYST",
      "manager": 7566,
      "hiredate": "1981-12-03 00:00:00",
      "salary": 3000,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 20,
        "dname": "RESEARCH",
        "loc": "DALLAS"
      }
    },
    {
      "insertTime": "2023-10-19 01:37:39",
      "updateTime": null,
      "eno": 7934,
      "ename": "MILLER",
      "job": "CLERK",
      "manager": 7782,
      "hiredate": "1982-01-23 00:00:00",
      "salary": 1300,
      "commission": null,
      "department": {
        "insertTime": "2023-10-19 01:37:39",
        "updateTime": null,
        "dno": 10,
        "dname": "ACCOUNTING",
        "loc": "NEW YORK"
      }
    }
  ],
  "currentPage": 0
}
응답 파일이 저장되었습니다.
> 2023-10-19T103745.200.json

Response code: 200; Time: 623ms (623 ms); Content length: 4092 bytes (4.09 kB)

📖 양방향 조인

📂 Department.java 추가

//    양방향 조인 : 1) 순환참조 문제 - 해결 : @JsonManagedReference(부서)
//                                       @JsonBackReference(사원)
//                2) N + 1 문제
//    사용법 : @OneToMany(mappedBy = "사원_연결속성")
    @OneToMany(mappedBy = "department")
    @JsonManagedReference
    private Set<Employee> employee = new HashSet<>(); // 1:n(사원)
}

📂 Employee.java 추가

package com.example.jpacustomexam.model.exam04;

import com.example.jpacustomexam.model.BaseTimeEntity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpacustomexam.model.exam04
 * fileName : Employee
 * author : GGG
 * date : 2023-10-19
 * description :
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-19         GGG          최초 생성
 */
@Entity
@Table(name = "TB_EMPLOYEE")
@SequenceGenerator(
        name = "SQ_EMPLOYEE_GENERATOR"
        , sequenceName = "SQ_EMPLOYEE"
        , initialValue = 1
        , allocationSize = 1
)
@Setter
@Getter
@ToString(exclude = "department")   // 순환참조 방지
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
public class Employee extends BaseTimeEntity {
    //    @Id : Primary Key 에 해당
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "SQ_EMPLOYEE_GENERATOR"
    )
    @Column(columnDefinition = "NUMBER")
    private Integer eno;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String ename;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String job;

    @Column(columnDefinition = "NUMBER")
    private Integer manager;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String hiredate;

    @Column(columnDefinition = "NUMBER")
    private Integer salary;

    @Column(columnDefinition = "NUMBER")
    private Integer commission;

//    @Column(columnDefinition = "NUMBER")
//    private Integer dno; // 공통 컬럼(생략, 자동으로 생성해줌)
//    단방향 조인
//    사용법 : @JoinColumn(name = "조인컬럼명")
//    양방향 조인 시 : N + 1 문제 발생 - 조인이 안되고 각각 SQL문이 생성되는 현상
//                1) 즉시 로딩(EAGER) : 기본 설정 -> 지연 로딩(LAZY)
//                                     (fetch = FetchType.LAZY)
//                      optional = false -> 조인방법(inner, outerjoin)
//                2) inner join fetch : 조인 쿼리 생성
//                3) application.properties :
//                   N + 1 sql -> where in (?,?....?) 값으로 변경하는 옵션
//              spring.jpa.properties.hibernate.default_batch_fetch_size=1000
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "dno")
    @JsonBackReference
    private Department department;


}

📖 지연 로딩과 즉시로딩

JPA에서 지연로딩(lazy loading)과 즉시로딩(eager loading)은 중요한 개념중 하나입니다.

엔티티라는 객체의 개념으로 데이터베이스를 구현했기 때문에 연관관계를 가진 각 엔티티 클래스에는 연관관계가 있는 객체들이 필드에 존재하게 됩니다. 연관관계와 상관업싱 즉각 해당 엔티티의 값만 조회하고 싶거나 연관관계를 가진 테이블의 값도 조회하고 싶은 경우 등 여러 조건들을 만족하기 위해 등장한 개념이 지연로딩과 즉시로딩입니다.

 

📂 DepartmentService.java 추가

//    양방향 조인 예제 : fetch join
public List<Department> selectFetchJoin() {
    List<Department> page = departmentRepository.selectFetchJoin();

    return page;
}

📂 DepartmentRepository.java 추가

    //    양방향 조인 : fetch join -> Paging 안됨
    @Query(value = "select distinct d from Department d inner join fetch d.employee e ")
    List<Department> selectFetchJoin();

📂 DepartmentController.java 추가

    /** 양방향 조인 예제 */
    //    page=현재페이지번호(0 ~ n), size=전체페이지수
    @GetMapping("/dept/fetch/join")
    public ResponseEntity<Object> selectFetchJoin() {
        try {
            List<Department> page
                    = departmentService.selectFetchJoin();

            if (page.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(page, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

✅ 실행결과

더보기
GET http://localhost:8000/exam04/dept/fetch/join

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 19 Oct 2023 02:26:02 GMT
Keep-Alive: timeout=60
Connection: keep-alive

[
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7902,
        "ename": "FORD",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7788,
        "ename": "SCOTT",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7566,
        "ename": "JONES",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-04-02 00:00:00",
        "salary": 2975,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7369,
        "ename": "SMITH",
        "job": "CLERK",
        "manager": 7902,
        "hiredate": "1980-12-17 00:00:00",
        "salary": 800,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7876,
        "ename": "ADAMS",
        "job": "CLERK",
        "manager": 7788,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 1100,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7902,
        "ename": "FORD",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7788,
        "ename": "SCOTT",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7566,
        "ename": "JONES",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-04-02 00:00:00",
        "salary": 2975,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7369,
        "ename": "SMITH",
        "job": "CLERK",
        "manager": 7902,
        "hiredate": "1980-12-17 00:00:00",
        "salary": 800,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7876,
        "ename": "ADAMS",
        "job": "CLERK",
        "manager": 7788,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 1100,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 10,
    "dname": "ACCOUNTING",
    "loc": "NEW YORK",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7839,
        "ename": "KING",
        "job": "PRESIDENT",
        "manager": null,
        "hiredate": "1981-11-17 00:00:00",
        "salary": 5000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7782,
        "ename": "CLARK",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-06-09 00:00:00",
        "salary": 2450,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7934,
        "ename": "MILLER",
        "job": "CLERK",
        "manager": 7782,
        "hiredate": "1982-01-23 00:00:00",
        "salary": 1300,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7902,
        "ename": "FORD",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7788,
        "ename": "SCOTT",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7566,
        "ename": "JONES",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-04-02 00:00:00",
        "salary": 2975,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7369,
        "ename": "SMITH",
        "job": "CLERK",
        "manager": 7902,
        "hiredate": "1980-12-17 00:00:00",
        "salary": 800,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7876,
        "ename": "ADAMS",
        "job": "CLERK",
        "manager": 7788,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 1100,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 10,
    "dname": "ACCOUNTING",
    "loc": "NEW YORK",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7839,
        "ename": "KING",
        "job": "PRESIDENT",
        "manager": null,
        "hiredate": "1981-11-17 00:00:00",
        "salary": 5000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7782,
        "ename": "CLARK",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-06-09 00:00:00",
        "salary": 2450,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7934,
        "ename": "MILLER",
        "job": "CLERK",
        "manager": 7782,
        "hiredate": "1982-01-23 00:00:00",
        "salary": 1300,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7902,
        "ename": "FORD",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7788,
        "ename": "SCOTT",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7566,
        "ename": "JONES",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-04-02 00:00:00",
        "salary": 2975,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7369,
        "ename": "SMITH",
        "job": "CLERK",
        "manager": 7902,
        "hiredate": "1980-12-17 00:00:00",
        "salary": 800,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7876,
        "ename": "ADAMS",
        "job": "CLERK",
        "manager": 7788,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 1100,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7900,
        "ename": "JAMES",
        "job": "CLERK",
        "manager": 7698,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 950,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7698,
        "ename": "BLAKE",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-05-01 00:00:00",
        "salary": 2850,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7844,
        "ename": "TURNER",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-08 00:00:00",
        "salary": 1500,
        "commission": 0
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7499,
        "ename": "ALLEN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-20 00:00:00",
        "salary": 1600,
        "commission": 300
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7521,
        "ename": "WARD",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-02-22 00:00:00",
        "salary": 1250,
        "commission": 500
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7654,
        "ename": "MARTIN",
        "job": "SALESMAN",
        "manager": 7698,
        "hiredate": "1981-09-28 00:00:00",
        "salary": 1250,
        "commission": 1400
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7902,
        "ename": "FORD",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1981-12-03 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7788,
        "ename": "SCOTT",
        "job": "ANALYST",
        "manager": 7566,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 3000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7566,
        "ename": "JONES",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-04-02 00:00:00",
        "salary": 2975,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7369,
        "ename": "SMITH",
        "job": "CLERK",
        "manager": 7902,
        "hiredate": "1980-12-17 00:00:00",
        "salary": 800,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7876,
        "ename": "ADAMS",
        "job": "CLERK",
        "manager": 7788,
        "hiredate": "1987-07-13 00:00:00",
        "salary": 1100,
        "commission": null
      }
    ]
  },
  {
    "insertTime": "2023-10-19 02:20:28",
    "updateTime": null,
    "dno": 10,
    "dname": "ACCOUNTING",
    "loc": "NEW YORK",
    "employee": [
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7839,
        "ename": "KING",
        "job": "PRESIDENT",
        "manager": null,
        "hiredate": "1981-11-17 00:00:00",
        "salary": 5000,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7782,
        "ename": "CLARK",
        "job": "MANAGER",
        "manager": 7839,
        "hiredate": "1981-06-09 00:00:00",
        "salary": 2450,
        "commission": null
      },
      {
        "insertTime": "2023-10-19 02:20:28",
        "updateTime": null,
        "eno": 7934,
        "ename": "MILLER",
        "job": "CLERK",
        "manager": 7782,
        "hiredate": "1982-01-23 00:00:00",
        "salary": 1300,
        "commission": null
      }
    ]
  }
]
응답 파일이 저장되었습니다.
> 2023-10-19T112602.200.json

Response code: 200; Time: 17ms (17 ms); Content length: 13967 bytes (13.97 kB)

 

📖 1 : 1 관계

2) 1:1 - @OneToOne(핸드폰), @OneToOne(사람)
  • Person 과 Phone 모델 클래스 생성

📂 Person.java

package com.example.jpacustomexam.model.exam05;

import com.example.jpacustomexam.model.BaseTimeEntity;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpacustomexam.model.exam05
 * fileName : Person
 * author : GGG
 * date : 2023-10-19
 * description :
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-19         GGG          최초 생성
 */
@Entity
@Table(name="TB_PERSON")
@SequenceGenerator(
        name = "SQ_PERSON_GENERATOR"
        , sequenceName = "SQ_PERSON"
        , initialValue = 1
        , allocationSize = 1
)
@Getter
@Setter
//@ToString(exclude = "emp")
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
public class Person extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_PERSON_GENERATOR")
    @Column(columnDefinition = "NUMBER")
    private Integer no;     // 기본키

    @Column(columnDefinition = "VARCHAR2(255)")
    private String name;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String job;

//    1:1 관계 설정 : @OneToOne(사람:부모), @OneToOne(폰:자식)
//    사용법 : @OneToOne(mappedBy = "자식 속성명")
    @OneToOne(mappedBy = "person")
//    순환참조 해결
    @JsonManagedReference
    private Phone phone;

}

📂 Phone.java

package com.example.jpacustomexam.model.exam05;

import com.example.jpacustomexam.model.BaseTimeEntity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpacustomexam.model.exam05
 * fileName : Phone
 * author : GGG
 * date : 2023-10-19
 * description :
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-19         GGG          최초 생성
 */
@Entity
@Table(name="TB_PHONE")
@SequenceGenerator(
        name = "SQ_PHONE_GENERATOR"
        , sequenceName = "SQ_PHONE"
        , initialValue = 1
        , allocationSize = 1
)
@Getter
@Setter
//@ToString(exclude = "emp")
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
public class Phone extends BaseTimeEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_PHONE_GENERATOR")
    @Column(columnDefinition = "NUMBER")
    private Integer pno;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String pname;

    @Column(columnDefinition = "VARCHAR2(255)")
    private String vender;

//    1:1 관계
//    사용법 : @JoinColumn(name ="부모 공통컬럼")
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "no")
    @JsonBackReference
    private Person person;

}

 

반응형

+ Recent posts