반응형

JPA 란

JPA(Java Persistence API)는 자바 애플리케이션에서 관계형 데이터베이스와 객체 간의 매핑을 관리하는 표준 API입니다.

 

객체-관계 매핑(Object-Relational Mapping, ORM): 객체 지향 프로그래밍의 객체를 관계형 데이터베이스의 테이블에 매핑.

표준 인터페이스: JPA는 인터페이스를 제공하고, Hibernate, EclipseLink 등의 구현체를 통해 사용할 수 있음.

데이터베이스 독립성: 코드 변경 없이 다양한 데이터베이스에서 동작.

 

하이버네이트란

Hibernate는 자바 환경에서 객체 관계 매핑(Object-Relational Mapping, ORM) 프레임워크입니다. 이를 통해 자바 객체와 관계형 데이터베이스 간의 변환을 자동화할 수 있습니다. Hibernate는 JPA(Java Persistence API)의 주요 구현체 중 하나로, 객체 지향적인 방식으로 데이터베이스 작업을 수행할 수 있도록 도와줍니다.

 

1. 객체-관계 매핑 (ORM):

Hibernate는 자바 객체를 데이터베이스 테이블에 매핑하여, 객체 지향 프로그래밍과 관계형 데이터베이스의 패러다임을 연결합니다.

2. 자동화된 CRUD 작업:

Hibernate는 기본적인 CRUD(Create, Read, Update, Delete) 작업을 자동으로 처리합니다. 이를 통해 개발자는 SQL 쿼리를 직접 작성하지 않아도 됩니다.

3. 데이터베이스 독립성:

Hibernate는 다양한 데이터베이스를 지원하며, 데이터베이스에 종속되지 않는 코드를 작성할 수 있게 도와줍니다.

4. HQL (Hibernate Query Language):

SQL과 유사한 쿼리 언어를 제공하여 객체를 대상으로 쿼리를 작성할 수 있습니다.

5. 캐싱:

Hibernate는 1차 캐시(세션 수준 캐시)와 2차 캐시(전역 캐시)를 지원하여 데이터베이스 액세스를 최적화합니다.

6. 트랜잭션 관리:

Hibernate는 트랜잭션 관리를 지원하여 데이터 일관성과 무결성을 유지할 수 있도록 합니다.

 

 

 

jpa 사용방법

라이브러리 추가

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

 

Entity 정의

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    // Getters and Setters
}

 

Repository 정의

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
}

 

Service 클래스에서 사용

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }

    public Product saveProduct(Product product) {
        return productRepository.save(product);
    }
}

 

JPA와 JDBC의 관계

JPA를 사용하면 일반적으로 직접적인 JDBC 라이브러리를 사용할 필요가 없습니다. JPA는 JDBC를 추상화하여 객체 지향적인 방식으로 데이터베이스와 상호작용할 수 있게 해주기 때문입니다. 그러나 JPA는 내부적으로 JDBC를 사용하여 데이터베이스와 통신합니다.

 

JPA와 JDBC의 관계

 

JPA: Java Persistence API는 자바 객체를 관계형 데이터베이스의 테이블에 매핑하는 프레임워크입니다. 개발자는 객체 지향적인 방식으로 데이터베이스 작업을 수행할 수 있습니다.

JDBC: Java Database Connectivity는 자바에서 데이터베이스에 접속하고 SQL 쿼리를 실행하기 위한 API입니다. JDBC는 데이터베이스와의 저수준 통신을 처리합니다.

 

JPA는 내부적으로 JDBC를 사용하지만, 개발자가 직접 JDBC 코드를 작성할 필요는 없습니다. 대신 JPA의 리포지토리, 엔터티 매니저 등을 사용하여 데이터베이스 작업을 처리합니다.

 

JDBC 예제

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class Product {
    private Long id;
    private String name;
    private double price;

    // Getters and Setters
}

public class ProductDAO {
    private String jdbcURL = "jdbc:h2:mem:testdb";
    private String jdbcUsername = "sa";
    private String jdbcPassword = "password";

    private static final String INSERT_PRODUCTS_SQL = "INSERT INTO products (name, price) VALUES (?, ?)";
    private static final String SELECT_ALL_PRODUCTS = "SELECT * FROM products";

    public ProductDAO() {}

    protected Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(jdbcURL, jdbcUsername, jdbcPassword);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }

    public void insertProduct(Product product) {
        try (Connection connection = getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(INSERT_PRODUCTS_SQL)) {
            preparedStatement.setString(1, product.getName());
            preparedStatement.setDouble(2, product.getPrice());
            preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<Product> selectAllProducts() {
        List<Product> products = new ArrayList<>();
        try (Connection connection = getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(SELECT_ALL_PRODUCTS)) {
            ResultSet rs = preparedStatement.executeQuery();
            while (rs.next()) {
                Long id = rs.getLong("id");
                String name = rs.getString("name");
                double price = rs.getDouble("price");
                products.add(new Product(id, name, price));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return products;
    }
}

public class ProductService {
    private ProductDAO productDAO = new ProductDAO();

    public List<Product> getAllProducts() {
        return productDAO.selectAllProducts();
    }

    public void saveProduct(Product product) {
        productDAO.insertProduct(product);
    }
}

public class ProductController {
    private ProductService productService = new ProductService();

    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }

    public void saveProduct(Product product) {
        productService.saveProduct(product);
    }
}

 

 

요약

 

JPA 사용: JPA는 내부적으로 JDBC를 사용하지만, 개발자가 직접 JDBC 코드를 작성할 필요가 없습니다. JPA의 엔터티, 리포지토리, 서비스 계층을 통해 데이터베이스 작업을 쉽게 수행할 수 있습니다.

JDBC 사용: JDBC는 저수준의 데이터베이스 접근 방법으로, 개발자가 직접 SQL 쿼리와 데이터베이스 연결을 관리해야 합니다.

 

따라서 JPA를 사용하면 직접적인 JDBC 라이브러리 사용을 피할 수 있으며, 코드의 유지보수성과 생산성을 높일 수 있습니다.

반응형
반응형

@Id는 해당 프로퍼티가 테이블의 주키(primary key) 역할을 한다는 것을 나타낸다.


@GeneratedValue는 주키의 값을 위한 자동 생성 전략을 명시하는데 사용한다.


Primary 키 생성 전략으로 JPA가 지원하는 것은 아래의 네 가지이다.


1. AUTO : (persistence provider가) 특정 DB에 맞게 자동 선택

  데이터베이스 벤더에 의존하지 않고, 데이터베이스는 기본키를 할당하는 벙법
- 데이터베이스에 따라서 IDENTITY, SEQUENCE, TABLE 방법 중 하나를 자동으로 선택해주는 방법이다.
- 예를들어, Oracle일 경우 SEQUENCE를 자동으로 선택해서 사용합니다. 따라서, 데이터베이스를 변경해도 코드를 수정할 필요가 없다.


2. IDENTITY : DB의 identity 컬럼을 이용

  기본 키 생성을 데이터베이스에 위임하는 방법 (데이터베이스에 의존적)
  - 주로 MySQL, PostgresSQL, SQL Server, DB2에서 사용합니다.


3. SEQUENCE : DB의 시퀀스 컬럼을 이용

  데이터베이스 시퀀스를 사용해서 기본 키를 할당하는 방법 (데이터베이스에 의존적)
  - 주로 시퀀스를 지원하는 Oracle, PostgresSQL, DB2, H2에서 사용한다. 
  - @SequenceGenerator를 사용하여 시퀀스 생성기를 등록하고, 실제 데이터베이스의 생성될 시퀀스이름을 지정해줘야 한다.


4. TABLE : 유일성이 보장된 데이터베이스 테이블을 이용

  키 생성 테이블을 사용하는 방법
- 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만드는 방법이다.
- 테이블을 사용하므로, 데이터베이스 벤더에 상관없이 모든 데이터베이스에 적용이 가능하다.

postgres를 이용하여 테스트해보면 AUTO와 SEQUENCE는 실제 INSERT 쿼리가 일어나기 전에 다음 쿼리를 통해서 주키를 가져오는 것을 확인할 수 있다.

select nextval ('hibernate_sequence')


기본키 자동생성 사용방법

  • @Id 어노테이션을 사용한다.
  • @GeneratedValue를 사용한다.
  • @GeneratedValue에 원하는 키 생성 전략을 선택한다. (IDENTITY, SEQUENCE, TABLE, AUTO)

Sample 코드

@Entity
public class Team {
  @Id
  @Column(name = "team_id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
}


@Entity
@SequeceGenerator(name = "TEAM_SEQ_GENERATOR", sequenceName = "TEAM_SEQ", initialValue = 1, allocationSize = 1)
// name=식별자 생성기 이름, sequenceName=DB에 등록될 시퀀스이름, initialValue=최초시작하는 수, allocationSize=증가하는수)
public class Team {

  @Id
  @Column(name = "team_id")
  @GeneratedValue(strategy = GenerationType. SEQUENCE, generator = "TEAM_SEQ_GENERATOR")
  private Long id;

}

@Entity
@TableGenerator(name="TEAM_SEQ_GENERATOR", table="TEAM_SEQUENCES", pkColumnValue="TEAM_SEQ", allocationSize=1)
// name=식별자 생성기 이름, table=키생성 테이블 이름, pkColumnValue=DB에 등록될 시퀀스이름)
public class Team {
  @Id
  @Column(name = "team_id")
  @GeneratedValue(strategy = GenerationType. TABLE, generator = "TEAM_SEQ_GENERATOR")
  private Long id;

}

@Entity
public class Team {
  @Id
  @Column(name = "team_id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

}


참고문헌

ithub.tistory.com/24

 

반응형
반응형

jpa 를 사용하려면 @Entity 클래스를 먼저 생성해야 한다.

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name="coin.market_code")
public class MarketCode {

    @Id
    @Column(name = "market_code")
    private String marketCode;
    @Column(name = "korean_name")
    private String koreanName;
    @Column(name = "english_name")
    private String englishName;

    @Builder
    public MarketCode(String marketCode, String koreanName, String englishName) {
        this.marketCode = marketCode;
        this.koreanName = koreanName;
        this.englishName = englishName;
    }
}

 

먼저 데이터베이스에 저장하기 위해 유저가 정의한 클래스가 필요한데 그런 클래스를

Entity라고 한다

@Id

primary key를 가지는 변수를 선언하는 것을 뜻한다. @GeneratedValue 어노테이션은 해당 Id 값을

어떻게 자동으로 생성할지 전략을 선택할 수 있다. 

보통 일반적으로

@GeneratedValue(strategy = GenerationType.AUTO)

를 사용한다. DB에 맞게 자동으로 생성해주는 역할이다.

참고 -> juntcom.tistory.com/156 - GeneratedValue생성방법

@Table

별도의 이름을 가진 데이터베이스 테이블과 매핑한다. 기본적으로 @Entity로 선언된 클래스의 이름은 실제

데이터베이스의 테이블 명과 일치하는 것을 매핑한다. 따라서 @Entity의 클래스명과 데이터베이스의 테이블명이

다를 경우에 @Table(name=" ")과 같은 형식을 사용해서 매핑이 가능하다.

@Column

@Column 선언이 꼭 필요한 것은 아니다. 하지만 @Column에서 지정한 변수명과 데이터베이스의 컬럼명을

서로 다르게 주고 싶다면 @Column(name=" ") 같은 형식으로 작성하면 된다.

그렇지 않은 경우에는 기본적으로 멤버 변수명과 일치하는 데이터베이스 컬럼을 매핑한다.

컬럼에 언더바가 있을 경우에는 꼭 column 어노테이션을 사용해야 한다.

 

 

JpaRepository

public interface MarketCodeRepository extends JpaRepository<MarketCode, String> {

}

Spring Data JPA에서 제공하는 JpaRepository 인터페이스를 상속하기만 해도 되며,

인터페이스에 따로 @Repository등의 어노테이션을 추가할 필요가 없다



Spring Data JPA에서 제공하는 JpaRepository 인터페이스를 상속하기만 해도 되며,

인터페이스에 따로 @Repository등의 어노테이션을 추가할 필요가 없다

 

 

그렇게 JpaRepository를  단순하게 상속하는 것만으로 위의 인터페이스는 Entity 하나에 대해서

아래와 같은 기능을 제공하게 된다.

 method

 기능

 save()

 레코드 저장 (insert, update)

 findOne()

 primary key로 레코드 한건 찾기
 findAll()

 전체 레코드 불러오기. 정렬(sort), 페이징(pageable) 가능

 count()  레코드 갯수
 delete()  레코드 삭제

 

public interface MarketCodeRepository extends JpaRepository<MarketCode, String> {
	List<MarketCode> findBykoreanName(String koreanName);
}

주의사항 변수명을 korean_name 처럼 언더바로 사용할시에 findBy가 적용이 안된다.

변수명을 카멜케이스로 맞추자.

 

Query 메소드에 포함할 수 있는 키워드는 다음과 같다.

메서드 이름 키워드

 샘플

 설명

 And

 findByEmailAndUserId(String email, String userId)

 여러필드를 and 로 검색

 Or

 findByEmailOrUserId(String email, String userId)

 여러필드를 or 로 검색

 Between

 findByCreatedAtBetween(Date fromDate, Date toDate)

 필드의 두 값 사이에 있는 항목 검색

 LessThan

 findByAgeGraterThanEqual(int age)

 작은 항목 검색

 GreaterThanEqual

 findByAgeGraterThanEqual(int age)

 크거나 같은 항목 검색

 Like

 findByNameLike(String name)

 like 검색

 IsNull

 findByJobIsNull()

 null 인 항목 검색

 In

 findByJob(String … jobs)

 여러 값중에 하나인 항목 검색

 OrderBy

 findByEmailOrderByNameAsc(String email)

 검색 결과를 정렬하여 전달

 


참고문헌

docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#jpa.sample-app.finders.strategies  - jpa문서
반응형
반응형

엔티티 클래스로 등록한 클래스지만, DB 테이블과는 별도로 기능이(추가 필드나 메소드) 필요한 경우가 있다.

 

예를 들어 DB 테이블에는 존재하지 않지만, 엔티티 클래스에는 등록되어 같이 운용하는 경우가 있다.

vo(엔티티) 에는 사용하지만 jpa 로 디비와 관련 없이 사용하고 싶을때!!

 

이럴 경우, DB 테이블에 간섭하지 않고, 엔티티 클래스 내부에서만 동작하게 하는 어노테이션을 사용한다.

 

@Transient 어노테이션을 사용하는데, 이 어노테이션은 하이버네이트의 jpa 패키지에 위치하고 있다.

@Transient 어노테이션을 사용한 필드나 메소드는 DB 테이블에 적용되지 않는다.

 

@Entity
public class Member {
    private Long memberId;
    private String password;
    @Transient
    private String confirmPassword;
    …
}

 

반응형

+ Recent posts