[Spring] CH17 스프링부트 레파지토리(저장소) - Hibernate JPQL (책)

jaegeunsong97·2023년 3월 21일
0

[Fast Campus] Spring

목록 보기
29/44
post-thumbnail

https://github.com/codingspecialist/Springboot-Hirbernate.git

📕 Hibernate


스프링부트에서 Hibernate는 ORM(Object-Relational Mapping) 기술을 사용하여 데이터베이스와의 상호 작용을 쉽게 할 수 있도록 지원합니다.

Hibernate를 사용하면 자바 객체와 데이터베이스 테이블 간의 매핑을 쉽게 설정할 수 있으며, 객체를 데이터베이스에 저장, 검색, 수정 및 삭제할 수 있습니다. Hibernate는 이러한 기능을 제공하기 위해 JPA(Java Persistence API)를 구현하며, JPA는 Java에서 ORM을 구현하기 위한 API 표준입니다.

스프링부트에서 Hibernate를 사용하려면, spring-boot-starter-data-jpa 의존성을 추가하고, application.properties 파일에 데이터베이스 연결 정보를 설정합니다.

또한, Entity 클래스를 작성하여 데이터베이스와 매핑을 설정합니다. Entity 클래스는 데이터베이스 테이블과 매핑됩니다.

Hibernate를 사용하면 데이터베이스 연결, 트랜잭션 관리 등의 기능을 쉽게 구현할 수 있습니다. 또한, Hibernate는 캐싱, 지연로딩 등의 기능을 제공하여 성능을 향상시킬 수 있습니다.

📕 ORM


OM은 객체지향 프로그래밍 언어에서 데이터베이스에 저장된 데이터를 객체로 변환하는 기술을 말합니다. 이때, 객체와 데이터베이스 사이의 매핑을 수동으로 정의하고 구현합니다.

ORM은 객체지향 프로그래밍 언어와 관계형 데이터베이스 사이의 데이터를 변환하는 기술로, ORM 프레임워크가 자동으로 객체와 테이블 간의 매핑을 수행합니다.

ORM은 JPA(Java Persistence API)와 같은 표준 API를사용하여 데이터베이스와 연동할 수 있습니다.

즉, OM은 ORM의 일종으로 볼 수 있습니다. OM은 ORM보다 덜 복잡하지만, 매핑 작업을 직접 수행해야 하므로 시간과 노력이 더 필요합니다. ORM은 매핑 작업을 자동화하여 생산성을 높이고, 객체지향적인 코드 작성을 촉진합니다.

📕 의존성


H2 데이터베이스는 오픈 소스 기반의 경량형 인메모리 데이터베이스로, 자바에서 사용할 수 있습니다. 스프링부트에서는 H2 데이터베이스를 기본적으로 지원하며, 별도의 설정 없이 쉽게 사용할 수 있습니다.

H2 데이터베이스는 다음과 같은 특징을 가지고 있습니다.

  1. 인메모리 데이터베이스로서 파일로 저장되지 않습니다.
  2. 경량형 데이터베이스이기 때문에 실행 속도가 빠릅니다.
  3. JDBC API를 지원하므로 자바에서 간단하게 사용할 수 있습니다.
  4. MySQL, PostgreSQL 등과 유사한 SQL 문법을 지원합니다.
  5. 쿼리 결과를 웹 브라우저를 통해 확인할 수 있는 콘솔 기능을 제공합니다.
dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  compileOnly 'org.projectlombok:lombok'
  developmentOnly 'org.springframework.boot:spring-boot-devtools'
  runtimeOnly 'com.h2database:h2'
  annotationProcessor 'org.projectlombok:lombok'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

📕 Application.yml 설정


  1. Oracle 모드 jdbc:h2:mem:test;MODE=Oracle Oracle 데이터베이스와 유사한 기능을 제공합니다.
  2. PostgreSQL 모드 jdbc:h2:mem:test;MODE=PostgreSQL PostgreSQL 데이터베이스와 유사한 기능을 제공합니다.
  3. DB2 모드 jdbc:h2:mem:test;MODE=DB2 IBM DB2 데이터베이스와 유사한 기능을 제공합니다.
  4. MSSQLServer 모드 jdbc:h2:mem:test;MODE=MSSQLServer Microsoft SQL Server 데이터베이스와 유사한 기능을 제공합니다.
  5. MySQL 모드 jdbc:h2:mem:test;MODE=MySQL

application.yml

server:
  port: 8080
  servlet:
    encoding:
      charset: utf-8
      force: true
spring:
  datasource:
    url: jdbc:h2:mem:test;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        format_sql: true

ddl-auto를 설정하면 @Entity로 선언된 객체의 테이블을 서버실행시에 생성해줍니다. 만약에 테이블이 존재한다면 drop후에 다시 생성해줍니다.

show-sql: true로 설정하면 hibernate가 실행하는 쿼리를 로그로 보여줍니다.

h2.console.enabled: true로 설정하면 localhost:8080/h2-console 에서 DB를 다룰 수 있게 됩니다.

📕 Entity


model/Customer.java

package shop.mtcoding.hibernatestudy.model;

import lombok.Getter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Getter
@Entity
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String tel;

    public Customer() {
        System.out.println("Jackson 발동시 디폴트 생성자 실행");
    }

    public Customer(Long id, String name, String tel){
        System.out.println("조회시에 mapper 동작할 때 풀 생성자 실행");
        this.id = id;
        this.name = name;
        this.tel = tel;
    }

    public void update(String name, String tel){
        this.name = name;
        this.tel = tel;
    }
}

@GeneratedValue(strategy = GenerationType.IDENTITY) 이외에도 Hibernate에서는 다음과 같은 자동 생성 전략을 제공합니다.

  1. GenerationType.AUTO: 데이터베이스에 따라 자동으로 GenerationType.IDENTITY, GenerationType.SEQUENCE, GenerationType.TABLE 중 하나를 선택합니다.

  2. GenerationType.SEQUENCE: 데이터베이스 시퀀스를 이용하여 PK 값을 생성합니다. 이 전략을 사용할 때는 @SequenceGenerator 어노테이션을 이용하여 시퀀스를 생성해야 합니다.

  3. GenerationType.TABLE: 데이터베이스에 별도의 테이블을 생성하여 PK 값을 관리합니다. 이 전략을 사용할 때는 @TableGenerator 어노테이션을 이용하여 테이블을 생성해야 합니다.

  4. GenerationType.IDENTITY: 데이터베이스의 Identity 컬럼을 이용하여 PK 값을 생성합니다. 이 전략을 사용할 때는 데이터베이스가 Identity 컬럼을 지원하는지 확인해야 합니다

GenerationType.IDENTITY는 데이터베이스의 Identity 컬럼을 이용하여 PK 값을 생성하는 자동 생성 전략입니다. 이 때, 데이터베이스의 Identity 컬럼이란 데이터베이스에서 자동으로 값을 생성해주는 기능을 가진 컬럼을 의미합니다. 이 기능을 지원하는 데이터베이스에는 MySQL, SQL Server, PostgreSQL 등이 있습니다.

그러나 Identity 컬럼이 지원되지 않는 데이터베이스에서 GenerationType.IDENTITY 전략을 사용할 수 없습니다. 이 경우에는 다른 자동 생성 전략을 사용해야 합니다. 그리고 데이터베이스의 Identity 컬럼이 제대로 설정되어 있지 않으면, GenerationType.IDENTITY 전략을 사용해도 PK 값을 제대로 생성하지 못할 수 있습니다.

따라서 데이터베이스의 Identity 컬럼이 잘 설정되어 있는지 확인하고, 사용 가능한 데이터베이스인지 여부를먼저 파악해야 합니다.

📕 CreateNativeQuery


package shop.mtcoding.hibernatestudy.model;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;

@Slf4j
@Repository
public class CustomerNativeQueryRepository {
    private EntityManager em;

    public CustomerNativeQueryRepository(EntityManager em) {
        this.em = em;
    }

    @Transactional
    public void save(Customer customer) {
        Query query = em.createNativeQuery("INSERT INTO customer (name, tel) VALUES (:name, :tel)");
        query.setParameter("name", customer.getName());
        query.setParameter("tel", customer.getTel());
        query.executeUpdate();
    }

    @Transactional
    public void update(Customer customer) {
        Query query = em.createNativeQuery("UPDATE customer SET name = :name, tel = :tel WHERE id = :id");
        query.setParameter("name", customer.getName());
        query.setParameter("tel", customer.getTel());
        query.setParameter("id", customer.getId());
        query.executeUpdate();
    }

    @Transactional
    public void delete(Customer customer) {
        Query query = em.createNativeQuery("DELETE FROM customer WHERE id = :id");
        query.setParameter("id", customer.getId());
        query.executeUpdate();
    }

    public Customer findById(Long id) {
        Query query = em.createNativeQuery("SELECT * FROM customer WHERE id = :id", Customer.class);
        query.setParameter("id", id);
        return (Customer) query.getSingleResult();
    }

    public List<Customer> findAll(int page) {
        final int row = 2;
        Query query = em.createNativeQuery("select * from customer limit :page, :row", Customer.class);
        query.setParameter("page", page*row);
        query.setParameter("row", row);
        return query.getResultList();
    }
}

📕 CreateQuery (JPQL)


package shop.mtcoding.hibernatestudy.model;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.util.List;

@Slf4j
@Repository
public class CustomerRepository {
    private EntityManager em;

    public CustomerRepository(EntityManager em) {
        this.em = em;
    }

    @Transactional
    public void save(Customer customer) {
        em.persist(customer);
    }

    @Transactional
    public void update(Customer customer) {
        em.merge(customer);
    }

    @Transactional
    public void delete(Customer customer) {
        em.remove(customer);
    }

    public Customer findById(Long id) {
        return em.find(Customer.class, id);
    }

    public List<Customer> findAll(int page) {
        final int row = 2;
        return em.createQuery("select ct from Customer ct", Customer.class)
                .setFirstResult(page*row)
                .setMaxResults(row)
                .getResultList();
    }
}

📕 영속화


Hibernate에서 영속화(Persistence)는 엔티티 객체를 데이터베이스와 연결하여 영구적으로 저장하는 과정을의미합니다. 영속화를 하기 위해서는 엔티티 객체를 영속성 컨텍스트(Persistence Context)에 추가해야 합니다.

영속성 컨텍스트는 엔티티 객체를 관리하는 Hibernate의 핵심 메커니즘 중 하나로, 영속화된 엔티티 객체를 캐싱하고, 변경된 내용을 추적하여 데이터베이스에 반영합니다.

Hibernate에서는 다음과 같은 영속화 관련 메소드를 제공합니다.

  1. persist(entity) 영속성 컨텍스트에 엔티티 객체를 추가하여 영속화합니다. 이 때, 엔티티 객체는 데이터베이스에 저장되지 않은 상태이며, 영속성 컨텍스트 내에만 존재합니다. persist() 메소드는 엔티티 객체를 반환하지 않으며, void 타입을 반환합니다.

  2. merge(entity) 엔티티 객체를 영속성 컨텍스트에 추가하거나, 이미 존재하는 엔티티 객체를 가져와서 변경된 내용을 데이터베이스에 반영합니다. merge() 메소드는 변경된 엔티티 객체를 반환하며, 이를 통해엔티티 객체를 계속 사용할 수 있습니다.

  3. flush() 영속성 컨텍스트에 있는 엔티티 객체의 변경 내용을 데이터베이스에 반영합니다. 이 때, 데이터베이스에 저장되지 않은 엔티티 객체는 데이터베이스에 저장되지 않습니다. flush() 메소드는 void 타입을 반환합니다.

  4. clear() 영속성 컨텍스트에 있는 모든 엔티티 객체를 제거합니다. 이 때, 변경된 내용은 데이터베이스에반영되지 않습니다. clear() 메소드는 void 타입을 반환합니다.

profile
블로그 이전 : https://medium.com/@jaegeunsong97

0개의 댓글