본문 바로가기
JPA

Spring Data JPA 에서 getOne 과 findById 차이점

by Gil Granger 2019. 10. 25.

Spring Data JPA에서 getOne과 findById의 차이점은 무엇일까?


기본 데이터 저장소에서 개체를 검색하는 데 findById()및 getOne()메서드가 모두 사용된다. 그러나 레코드를 검색하는 기본 메커니즘은이 두 메소드에서 서로 다르다. 실제로 getOne ()은 데이터베이스에 충돌하지 않는 Lazy 조작이다.

getOne () 메소드

getOne ()은 주어진 식별자를 가진 엔티티에 대한 참조를 반환한다. getOne은 내부적으로 EntityManager.getReference () 메소드를 호출한다. 문서에 따라 이 메소드는 데이터베이스에 충돌하지 않고 항상 프록시를 반환한다. (Lazy지연으로 가져온) 요청 된 엔티티가 데이터베이스에 존재하지 않으면이 메소드는 실제 액세스시 EntityNotFoundException을 발생시킨다.

EntityManager.getReference (Class, Object)

상태를 Lazy하게 가져올 수있는 인스턴스를 가져온다.. 요청 된 인스턴스가 데이터베이스에 없으면 인스턴스 상태에 처음 액세스 할 때 EntityNotFoundException이 발생한다.. 지속성 제공자 런타임은 getReference가 호출 될 때 EntityNotFoundException을 발생시킬 수 있다. 애플리케이션은 엔티티 관리자가 열려있는 동안 애플리케이션이 액세스하지 않는 한 분리시 인스턴스 상태를 사용할 수있을 것으로 예상해서는 안된다.

findById () 메소드

이 메소드는 실제로 데이터베이스에 도달하고 실제 오브젝트 맵핑을 데이터베이스의 행에 리턴한다. 데이터베이스에 레코드가없는 경우 널을 리턴하는 것은 EAGER로드 한것이다.

어느 것을 선택해야하는가?

이 방법들 사이의 유일한 차이점은 성능에 관한 것이다.. 지연로드 된 getOne () 메소드는 리턴 된 프록시 오브젝트의 특성에 실제로 액세스 할 때까지 데이터베이스에 도달하지 않으므로 JVM에서 데이터베이스 왕복을 피한다..

데이터베이스에서 엔터티를 가져 와서 다른 개체에 대한 참조로 할당하고 관계 (OneToOne 또는 ManyToOne)를 유지하려는 시나리오가 있다.. 구체적인 예를 보면,

 

 

 

부서에 속한 직원이 있다.

 

@Entity
@Table(name = "t_departments")
public class Department {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    private String name;
    
}

@Entity
@Table(name = "t_employees")
public class Employee {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    private String name;

    @ManyToOne  
    private Department department;
    
 }

 

 

원 개체에는 부서에 대한참조가 필요하다.

이제 새 직원을 작성하여 부서에 할당하려는 다음 코드로 고려해보자.

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class HRService {

    @Autowired
    private DepartmentRepository departmentRepository;

    @Autowired
    private EmployeeRepository employeeRepository;

    public Department createDepartment() {
        Department dept = new Department();
        dept.setName("Product & Engg");
        return departmentRepository.save(dept);
    }

    public void createEmployee1(long deptId) {
        final Department pne = departmentRepository.getOne(deptId); 
        Employee employee = new Employee();
        employee.setName("Foo 1");
        employee.setDepartment(pne);
        employeeRepository.save(employee);
    }
    
 }

부서 개체에 대한 참조를 검색하여 직원에게 할당하고 있다. 부서 개체의 세부 정보를 가져올 필요가 없기 때문에 이 특별한 경우  findById()보다 getOne() 사용하는 것이 좋다.

 

 

insert into t_employees (department_id, name, id) values (?, ?, ?)

 

 

getOne()대신에 findById() 사용 하면 아래 코드와 같이 데이터베이스를 추가로 호출하여 부서 개체를 검색한다.

public void createEmployee2(long deptId) {
       Optional<Department> pne = departmentRepository.findById(deptId);
       Employee employee = new Employee();
       employee.setName("Foo 1");
       pne.ifPresent(department -> {
           employee.setDepartment(department);
       });
       employeeRepository.save(employee);
 }

 

select department0_.id as id1_4_0_, department0_.name as name2_4_0_ from t_departments department0_ where department0_.id=?


insert into t_employees (department_id, name, id) values (?, ?, ?)

 

여기서는 부서 레코드를 열심히 가져 와서 직원 레코드에서 참조로 지정하기 위해 데이터베이스에 대한 추가 호출이 수행되었음을 알 수 있다.

 

 

 

 

비교 요약

getOne ()                                                                         findById ()

대상 엔터티에 대한 지연로드 된 참조

주어진 ID에 대한 엔티티를 실제로 로드

객체의 속성에 액세스 할 필요가없는 경우에만 유용

모든 속성에 액세스 할 수 있도록 객체가 로드 됨

액세스 호출시 실제 오브젝트가 존재하지 않으면 EntityNotFoundException을 던짐.

주어진 ID에 해당하는 실제 객체가 존재하지 않으면 null을 반환

더 나은 성능

데이터베이스에 대한 추가 왕복이 필요

댓글