Back-end/Spring

[Spring] ORM, JPA, Hibernate, JDBC, Spring Data JPA 개념 정리

영벨롭 2023. 8. 7. 21:16

★ ORM, Spring Data JPA, JPA, Hibernate, JDBC, 그리고 관계형 데이터베이스


★ ORM

 ORM 은 Object Relational Mapping 의 약자로 관계형 데이터를 객체로 표현하는 프로그래밍 기법 또는 기술입니다. 

 

 대부분의 프로그래밍 언어는 Object(객체)를 사용하고, 관계형 데이터베이스는 Table(테이블) 내부에서 Row(로우) 단위로 사용합니다. 

 이는 관계형 데이터베이스에서 사용하는 자료의 형태가 객체 지향 관점에서 맞지 않아 한계에 부딪히게 됩니다. 

 

 ORM 은 이러한 간극을 해소하기 위해 객체와 DB 테이블이 매핑을 이루는 것이라고 볼 수 있으며, 코드 상에서 생성한 객체를 조작함으로써 DB 를 조작할 수 있게 됩니다. 

 즉, 자바 Object 와 데이터베이스의 Table 데이터를 자동으로 연결해주는 것입니다. 

 

 ORM 을 사용하면 SQL 문이 아닌 Method 를 통해 DB 를 조작할 수 있어, 개발자는 객체 모델을 이용하여 비지니스 로직을 구성하는 데에만 집중할 수 있게 됩니다. 

(예시: SELECT * FROM user; 선언문의 결과를 user.findAll() 메서드를 실행함으로써 얻을 수 있다)

 

 자바의 ORM 을 위한 표준 기술로 Hibernate, Spring JPA 등과 같은 구현체가 있고, 이것의 표준 인터페이스가 JPA 입니다.


★ JPA

 JPA 는 Java Persistence API 의 약자로 자바에서 사용하는 ORM 입니다. 

 

 라이브러리가 아닌, 자바 Application 에서 RDBMS 를 사용하는 방식을 정의한 인터페이스입니다.

 단순한 기술 명세이기 때문에 JPA 를 구현하는 구현체는 따로 존재하기 때문에 구현부는 존재하지 않습니다. 

 

 즉, JPA 자체는 관계형 데이터를 객체로 표기하는 기능 뿐입니다.

 


★ Hibernate

 Hibernate 는 자바에서 ORM 을 사용할 때 사용하는 프레임워크로, JPA 인터페이스를 구현하는 여러 종류의 실체 구현체 중 가장 많이 사용하는 것이 Hibernate 입니다.

 즉, Hibernate 는 JPA 의 구현체(JPA를 implements 하여 구현한 class 라이브러리)라고 할 수 있습니다. 

 

 Hibernate 를 사용하면 직접 SQL 을 호출하지 않아도, Java 에서 메소드를 호출하는 것만으로 DB 데이터를 CRUD 할 수 있습니다. 

 


★ Spring Data JPA

 Spring Data JPA 는 JPA 를 사용하기 편하도록 추가적인 기능을 제공하는 라이브러리/프레임워크로, JPA 를 한 단계 더 추상화한 Repository 인터페이스를 제공합니다.

 Hibernate 와 같은 JPA 구현체를 사용해서 JPA 를 사용하게 되며, 이로써 사용자는 더욱 간단하게 데이터를 접근할 수 있습니다. 

 

 즉, Hibernate 는 JPA 구현체이고, Spring Data JPA 는 JPA 에 대한 데이터 접근의 추상화입니다. 

 

 Repository 인터페이스를 제공함으로써 이루어지는데, 사용자가 Repository 인터페이스에 정해진 규칙대로 메서드를 입력하면 Spring 이 알아서 해당 메서드 이름에 적합한 쿼리를 날리는 구현체를 만들어 Bean 으로 등록해 줍니다. 

 

PostRepository.java

package com.dev.demojpa.repository;

import com.dev.demojpa.entity.BoardEntity;
import com.dev.demojpa.entity.PostEntity;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface PostRepository extends CrudRepository<PostEntity, Long> {
    List<PostEntity> findAllByWriter(String writer); // where writer = ?
    List<PostEntity> findAllByWriterAndBoardEntity(String writer, BoardEntity boardEntity); // where writer = ? and board_entity_id = ?
    List<PostEntity> findAllByWriterContaining(String writer); // writer 를 포함하는 PostEntity

}

PostDao.java

package com.dev.demojpa.dao;

import com.dev.demojpa.dto.PostDto;
import com.dev.demojpa.entity.PostEntity;
import com.dev.demojpa.repository.PostRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Repository;
import org.springframework.web.server.ResponseStatusException;

import java.util.Iterator;
import java.util.Optional;

@Repository
public class PostDao {
    private static final Logger logger = LoggerFactory.getLogger(PostDao.class);
    private final PostRepository postRepository;

    public PostDao(
            @Autowired PostRepository postRepository
            ) {
        this.postRepository = postRepository;
    }

    public void createPost(PostDto dto) {
        PostEntity postEntity = new PostEntity();
        postEntity.setTitle(dto.getTitle());
        postEntity.setContent(dto.getContent());
        postEntity.setWriter(dto.getWriter());
        postEntity.setBoardEntity(null);

        this.postRepository.save(postEntity);
    }

    public PostEntity readPost(int id) {
        Optional<PostEntity> postEntity = this.postRepository.findById((long) id);
        if(postEntity.isEmpty()) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
        return postEntity.get();
    }

    public Iterator<PostEntity> readPostAll() {
        return this.postRepository.findAll().iterator();
    }

    public void updatePost(int id, PostDto dto) {
        Optional<PostEntity> targetEntity = this.postRepository.findById(Long.valueOf(id));

        if(targetEntity.isEmpty()) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
        PostEntity postEntity = targetEntity.get();

        postEntity.setTitle(dto.getTitle() == null ? postEntity.getTitle() : dto.getTitle());
        postEntity.setContent(dto.getContent() == null ? postEntity.getContent() : dto.getContent());

        // save 메소드는 update, create 둘 다 됨
        this.postRepository.save(postEntity);
    }

    public void deletePost(int id) {
        Optional<PostEntity> targetEntity = this.postRepository.findById((long) id);
        if(targetEntity.isEmpty()) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        }
        this.postRepository.delete(targetEntity.get());
    }
}

 


★ JDBC

 JDBC 는 Java Database Connectivity의 약자로 자바에서 DB 프로그래밍을 하기 위해 사용되는 API 입니다.

 즉, 데이터베이스와 통신하기 위한 API 입니다.

 

 JDBC 는 왜 나타났을까요?

 데이터베이스에는 여러 종류가 있는데, 어플리케이션 개발 중 데이터베이스의 종류를 변경하게 되면 데이터베이스에 통신하는 코드 또한 변경해야 한다는 문제점이 있었습니다.

 이때 사용하는 데이터베이스를 교체하더라도, 데이터베이스의 종류에 상관없이 똑같은 코드로 해결이 가능하도록 하는 것이 바로 JDBC 입니다. 

 

 JDBC API 는 설정한 데이터베이스에 맞는 드라이버를 사용하여 데이터베이스에 접근하여, 데이터베이스와 연결하고 영속성 데이터를 저장할 수 있게 합니다. 

 

 

반응형