2023. 4. 17. 09:34ㆍJPA
JPA 실습 프로젝트 구성
pom.xml 설정
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hellojpa</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- JPA, 하이버네이트 버전 -->
<hibernate.version>5.6.15.Final</hibernate.version>
<!-- 데이터베이스 버전 -->
<h2db.version>2.2.224</h2db.version>
</properties>
<dependencies>
<!-- JPA, 하이버네이트 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- H2 데이터베이스 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2db.version}</version>
</dependency>
</dependencies>
</project>
persistence.xml 설정
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
<persistence-unit name="jpabook">
<properties>
<!-- 필수 속성 -->
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<!-- 옵션 -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.id.new_generator_mappings" value="true" />
<!-- create, update, validate, create-drop, none 중 택 -->
<property name="hibernate.hbm2ddl.auto" value="update" />
<!-- 기본 매핑 이름 -->
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
</properties>
</persistence-unit>
</persistence>
인텔리제이 프로젝트 구성
H2 Database 설치
H2 데이터베이스를 설치합니다.
설치 완료 후, H2 콘솔을 실행시킵니다.
H2 콘솔이 정상적으로 실행되었다면, 위 그림처럼 웹 브라우저가 실행됩니다.
단, 주의할 점은 웹 브라우저의 주소 입력란의 private address와 현재 local host PC의 private address와 일치해야 합니다. 그리고 포트넘버가 8282인지를 확인해야 합니다.
private address가 일치하지 않는다면, 손쉽게 private address 대신 localhost 도메인을 사용하면 됩니다
위 그림처럼 설정을 하고 연결 버튼을 선택합니다.
만약 아래 그림처럼 연결되지 않는다는 에러 메시지가 발생한다면,
아래 그림처럼 H2 Database Engine 트레이의 Create a new database...을 선택합니다
아래 그림처럼 대화상자가 실행됩니다.
그리고 이 대화상자에 아래 그림처럼 원하는 경로에 test 디렉토리를 생성하고 원하는 Username과 Password를 설정합니다.
(아래 대화상자에 입력한 모든 정보를 기억해야 합니다)
설정이 정상 완료된다면 H2 콘솔창에 다신 연결 버튼을 선택합니다.
위 그림처럼 웹 브라우저가 페이지를 렌더링한다면 정상적으로 H2 데이터베이스를 운영할 수 있습니다.
h2 콘솔에서 다음 쿼리를 적용합니다.
CREATE TABLE member (
id varchar(255) primary key,
name varchar(255),
age integer
)
아래처럼 쿼리 입력창에 쿼리를 작성하고 실행 버튼을 선택합니다.
아래 그림처럼 member 테이블이 생성된 것을 확인할 수 있습니다.
다음과 같은 쿼리로 member 테이블에 row를 입력합니다.
INSERT INTO member (id, name, age) VALUES ('1', 'John', 30);
쿼리 입력창에 다수의 쿼리를 선별적으로 실행할 수 있습니다.
(실행하고자 하는 쿼리문을 단건으로 하이라이트한 후 실행 버튼을 선택합니다)
member 테이블을 생성할 때, id 프라이머리 키를 not null로 설정하지 않아도 디폴트로 not null이 적용됩니다.
다음과 같은 쿼리로 특정 row을 삭제할 수 있습니다.
DELETE FROM member WHERE id = '1';
DELETE FROM member;
DROP TABLE member;
@DynamicUpdate
@DynamicInsert 어노테이션은 엔티티 객체가 데이터베이스에 삽입(insert)될 때, null 또는 default 값인 컬럼은 제외하고 삽입하는 기능을 제공합니다. 이를 통해 데이터베이스 테이블의 크기를 줄이고, 성능을 향상시킬 수 있습니다.
또한 @DynamicUpdate 어노테이션은 해당 엔티티의 수정 시, 변경된 필드만 Update 쿼리에 반영합니다.
Member 클래스에 @DynamicUpdate 어노테이션을 적용하지 않은 상태에서 특정 컬럼(NAME)을 업데이이트합니다.
@Entity
@Table(name = "MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String username;
// 매핑 정보가 없는 필드
private Integer age;
// 디퐅트 컨스트럭터를 정의
public Member() {
}
// 파라미터를 가지는 컨스트럭터 정의
public Member(final String id, final String username, final Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(final Integer age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Member{");
sb.append("id='").append(id).append('\'');
sb.append(", username='").append(username).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
}
package org.intheeast;
import org.intheeast.domain.Member;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Main {
static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jpabook");
public static void main(String[] args) {
createMember("id1", "sungwon");
updateMember("id1", "jihyung");
}
static Member createMember(final String id, final String username) {
// 영속성 컨텍스트 시작
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member();
em.persist(member);
tx.commit();
em.close(); // 영속성 컨텍스트 종료,
return member;
}
static Member updateMember(final String id, final String username) {
// 영속성 컨텍스트 시작
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = em.find(Member.class, "id1");
member.setUsername(username);
em.persist(member);
tx.commit();
em.close(); // 영속성 컨텍스트 종료,
return member;
}
}
아래는 위 코드를 수행하여 출력된 콘솔 내용입니다.
name 필드만 수정하였지만,
age 필드도 업데이트하는 것을 확인할 수 있습니다.
Hibernate:
/* insert org.intheeast.domain.Member
*/ insert
into
MEMBER
(age, NAME, ID)
values
(?, ?, ?)
Hibernate:
select
member0_.ID as id1_0_0_,
member0_.age as age2_0_0_,
member0_.NAME as name3_0_0_
from
MEMBER member0_
where
member0_.ID=?
Hibernate:
/* update
org.intheeast.domain.Member */ update
MEMBER
set
age=?,
NAME=?
where
ID=?
하지만 다음과 같이 @DynamicUpdate 어노테이션을 Member 클래스에 적용한다면,
@Entity
@Table(name = "MEMBER")
@DynamicUpdate // 변경된 필드만 update 쿼리에서 적용된다
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String username;
// 매핑 정보가 없는 필드
private Integer age;
// 디퐅트 컨스트럭터를 정의
public Member() {
}
// 파라미터를 가지는 컨스트럭터 정의
public Member(final String id, final String username, final Integer age) {
this.id = id;
this.username = username;
this.age = age;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(final Integer age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Member{");
sb.append("id='").append(id).append('\'');
sb.append(", username='").append(username).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
}
업데이트시, 실행 결과는 NAME 컬럼만 업데이트되는 것을 확인할 수 있습니다.
Hibernate:
/* insert org.intheeast.domain.Member
*/ insert
into
MEMBER
(age, NAME, ID)
values
(?, ?, ?)
Hibernate:
select
member0_.ID as id1_0_0_,
member0_.age as age2_0_0_,
member0_.NAME as name3_0_0_
from
MEMBER member0_
where
member0_.ID=?
Hibernate:
/* update
org.intheeast.domain.Member */ update
MEMBER
set
NAME=?
where
ID=?
@DynamicInsert
@DynamicInsert 어노테이션은 엔티티 객체가 데이터베이스에 삽입(insert)될 때, null 또는 default 값인 컬럼은 제외하고 삽입하는 기능을 제공합니다. 이를 통해 데이터베이스 테이블의 크기를 줄이고, 성능을 향상시킬 수 있습니다.
예를 들어, 다음과 같은 엔티티 클래스가 있다고 가정해보겠습니다.
package org.intheeast.domain;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
@Entity
@Table(name = "MEMBER")
@DynamicUpdate // 변경된 필드만 update 쿼리에서 적용 된다
@DynamicInsert
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME", nullable = false)
private String username;
@Column(name = "AGE", nullable = false)
private Integer userage;
private String phoneNumber;
// 디퐅트 컨스트럭터를 정의
public Member() {
}
// 파라미터를 가지는 컨스트럭터 정의
public Member(final String id, final String username, final Integer age) {
this.id = id;
this.username = username;
this.userage = age;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public Integer getAge() {
return userage;
}
public void setAge(final Integer age) {
this.userage = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Member{");
sb.append("id='").append(id).append('\'');
sb.append(", username='").append(username).append('\'');
sb.append(", age=").append(userage);
sb.append('}');
return sb.toString();
}
}
CREATE TABLE member (
id varchar(255) primary key,
name varchar(255) not null,
age integer not null,
phonenumber varchar(255)
)
위 쿼리에서 not null이 적용된 컬럼을 H2 콘솔에서 확인할 수 있습니다.
INFORMATION_SCHEMA의 COLUMNS 아이템을 클릭하면 아래 그림처럼 쿼리 입력창에 자동으로
COLUMNS에 대한 정보를 확인할 수 있습니다.
public class Main {
static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jpabook");
public static void main(String[] args) {
createMember("id1", "sungwon", 49, "01062789022");
// phonenumber를 생략한 Member 엔티티 클래스 객체를 생성한다
createMember("id2", "jihyung", 51);
}
static Member createMember(final String id, final String username, Integer age, String phonenumber) {
// 영속성 컨텍스트 시작
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member(id, username, age, phonenumber);
em.persist(member);
tx.commit();
em.close(); // 영속성 컨텍스트 종료,
return member;
}
static Member createMember(final String id, final String username, Integer age) {
// 영속성 컨텍스트 시작
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Member member = new Member(id, username, age);
em.persist(member);
tx.commit();
em.close(); // 영속성 컨텍스트 종료,
return member;
}
}
실행 결과는 다음과 같습니다.
Hibernate:
/* insert org.intheeast.domain.Member
*/ insert
into
MEMBER
(phoneNumber, AGE, NAME, ID)
values
(?, ?, ?, ?)
Hibernate:
/* insert org.intheeast.domain.Member
*/ insert
into
MEMBER
(AGE, NAME, ID)
values
(?, ?, ?)
위의 실행 결과를 보면, 두번째 insert 쿼리는 phoneNumber 값이 null 이므로, insert 쿼리에는 AGE, NAME과 ID 컬럼만 포함됩니다.
@Transient
@Transient는 엔티티 클래스의 필드나 메소드에 붙여서 해당 필드나 메소드를 영속화 과정에서 무시하도록 지정합니다. 즉, 데이터베이스 테이블과 매핑되지 않는다는 것을 의미합니다. 주로 다음과 같은 상황에서 사용됩니다:
1. 데이터베이스에 저장되지 않아야 할 임시적인 데이터가 필드에 존재할 때
2. 데이터베이스에 저장하지 않아도 되는 계산된 값이 필드에 존재할 때
3. 엔티티에 매핑된 데이터베이스 테이블이 아닌 다른 테이블에서 가져올 정보가 필요할 때
예를 들어, 다음과 같이 사용할 수 있습니다:
@Entity
@Table(name = "MEMBER")
@DynamicUpdate // 변경된 필드만 update 쿼리에서 적용 된다
@DynamicInsert
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME", nullable = false)
private String username;
@Column(name = "AGE", nullable = false)
private Integer userage;
private String phoneNumber;
@Transient
private String fullName;
// 디퐅트 컨스트럭터를 정의
public Member() {
}
// 파라미터를 가지는 컨스트럭터 정의
public Member(final String id, final String username, final Integer age) {
this.id = id;
this.username = username;
this.userage = age;
}
public Member(final String id, final String username, final Integer age, final String phoneNumber) {
this(id, username, age);
this.phoneNumber = phoneNumber;
}
public Member(final String id, final String username, final Integer age, final String phoneNumber, final String fullName) {
this(id, username, age, phoneNumber);
this.fullName = fullName;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public Integer getAge() {
return userage;
}
public void setAge(final Integer age) {
this.userage = age;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getFullName() {
return this.fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Member{");
sb.append("id='").append(id).append('\'');
sb.append(", username='").append(username).append('\'');
sb.append(", age=").append(userage);
sb.append(", phonenumber=").append(phoneNumber);
sb.append(", fullname=").append(fullName);
sb.append('}');
return sb.toString();
}
}
위의 예시에서 fullName 필드는 데이터베이스에 저장되지 않습니다.
(persistence.xml 파일에서 다음과 같이 설정하여 JPA가 MEMBER 테이블을 자동으로 생성하게 함으로써 확인할 수 있습니다)
<property name="hibernate.hbm2ddl.auto" value="create" />
하이버네이트가 생성한 테이블 생성 쿼리는 다음과 같습니다.
fullname 필드에 해당하는 컬럼을 생성하지 않음을 알 수 있습니다.
Hibernate:
drop table if exists MEMBER CASCADE
Hibernate:
create table MEMBER (
ID varchar(255) not null,
phoneNumber varchar(255),
AGE integer not null,
NAME varchar(255) not null,
primary key (ID)
)
※위의 쿼리에서 CASCADE는 외래 키 제약 조건이 있는 경우 해당 테이블의 행이 삭제될 때 참조하는 테이블의 행도 함께 삭제되도록 지정하는 옵션입니다.
예를 들어, MEMBER 테이블이 다른 테이블의 외래 키로 사용되고 있다고 가정해 봅시다. 이 경우 CASCADE 옵션이 적용된다면, MEMBER 테이블의 어떤 행이 삭제되면 이 행을 참조하고 있는 다른 테이블의 행도 함께 자동으로 삭제됩니다.
따라서 위의 코드에서 drop table if exists MEMBER CASCADE`는 MEMBER 테이블이 존재하는 경우 해당 테이블을 삭제하고, 이 테이블을 참조하고 있는 다른 테이블의 행도 함께 삭제한다는 의미입니다.
@SequenceGenerator
@SequenceGenerator는 Java Persistence API(JPA)에서 엔티티의 기본 키 값을 생성하기 위해 사용되는 어노테이션입니다. 이 어노테이션은 데이터베이스 시퀀스를 기반으로 기본 키(primary key)의 값을 자동으로 생성하는 전략을 정의할 때 사용됩니다.
데이터베이스 시퀀스는 일련번호를 순차적으로 생성하는 데이터베이스 객체로, 주로 기본 키 값을 자동으로 생성하는 데 사용됩니다. @SequenceGenerator 어노테이션은 이러한 시퀀스를 사용하여 엔티티의 기본 키 값을 생성하도록 JPA에 지시합니다.
@SequenceGenerator 어노테이션은 다음과 같은 주요 속성을 포함할 수 있습니다:
- name: 시퀀스 생성기의 이름을 지정합니다. 이 이름은 @GeneratedValue 어노테이션의 generator 속성에서 참조됩니다.
- sequenceName: 데이터베이스에 정의된 실제 시퀀스의 이름입니다.
- initialValue: 시퀀스의 시작 값입니다. 기본값은 1입니다.
- allocationSize: 시퀀스에서 한 번에 증가시킬 값을 지정합니다. 예를 들어, allocationSize가 1이면, 각각의 새 엔티티는 시퀀스에서 다음 값을 받습니다. 기본값은 50입니다.
예를 들어, Employee 엔티티의 기본 키를 시퀀스를 사용하여 생성하려면 다음과 같이 어노테이션을 사용할 수 있습니다:
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "employee_seq")
@SequenceGenerator(name = "employee_seq", sequenceName = "employee_sequence", initialValue = 1, allocationSize = 1)
private Long id;
// 다른 필드와 메서드
}
이 예에서 employee_seq라는 이름의 시퀀스 생성기가 정의되었고, employee_sequence라는 데이터베이스 시퀀스를 사용하여 Employee 엔티티의 id 필드에 대한 기본 키 값을 생성합니다. initialValue와 allocationSize는 각각 1로 설정되어 있어, 시퀀스는 1부터 시작하여 1씩 증가합니다.
@SequenceGenerator를 사용하면 애플리케이션에서 엔티티를 영속화할 때마다 JPA 구현체가 시퀀스를 사용하여 기본 키 값을 자동으로 생성하고 할당합니다. 이 방식은 특히 데이터베이스에서 자동 증가 필드(auto-increment field)를 지원하지 않는 경우 유용합니다.
※ allocationSize는 @SequenceGenerator 어노테이션에서 사용되는 속성 중 하나로, 주로 성능 최적화를 위해 사용됩니다. 이 속성은 JPA 프로바이더가 데이터베이스의 시퀀스 값을 얼마나 자주 증가시킬지를 결정합니다.
allocationSize가 1일 때, 데이터베이스 시퀀스는 엔티티의 각 새 인스턴스를 위해 1씩 증가합니다. 즉, 새 엔티티가 데이터베이스에 삽입될 때마다 시퀀스의 다음 값을 요청하여 해당 엔티티의 기본 키로 사용합니다. 이 경우, 엔티티가 생성될 때마다 데이터베이스에 시퀀스 값을 증가시키는 쿼리를 실행해야 하므로 데이터베이스와의 통신이 빈번하게 발생합니다.
반면, allocationSize가 50일 경우(기본값), JPA 프로바이더는 데이터베이스 시퀀스 값을 한 번에 50씩 증가시키고, 이 범위 내에서 메모리상에서 값을 관리합니다. 예를 들어, 시퀀스의 현재 값이 1이고 allocationSize가 50이라면, 첫 번째 엔티티가 생성될 때 시퀀스는 51로 증가하고, 이후 생성되는 엔티티는 2부터 50까지의 값을 메모리상에서 할당받습니다. 이렇게 되면, 다음 50개의 엔티티에 대해서는 데이터베이스에 추가적인 시퀀스 증가 요청을 하지 않아도 되므로 데이터베이스와의 통신이 줄어들고 성능이 향상됩니다.
allocationSize를 큰 값으로 설정하는 것은 시퀀스 값 할당에 대한 데이터베이스 요청의 수를 줄여 성능을 개선할 수 있지만, 애플리케이션 재시작이나 여러 인스턴스에서 동시에 엔티티를 생성하는 환경에서 시퀀스 값의 누락이나 중복이 발생할 수 있는 위험을 고려해야 합니다. 따라서, allocationSize를 설정할 때는 애플리케이션의 요구 사항과 운영 환경을 충분히 고려해야 합니다.
@TableGenerator
@TableGenerator는 JPA(Java Persistence API)에서 사용되는 어노테이션으로, 엔티티 클래스의 주요 키(primary key) 값을 자동으로 생성하기 위한 고급 자동 생성 전략을 정의할 때 사용됩니다. @TableGenerator를 사용하면 테이블을 사용하여 기본 키 값을 생성하고 관리하는 방식을 지정할 수 있습니다.
일반적으로 @GeneratedValue 어노테이션을 사용하여 기본 키 값을 자동으로 생성할 때는 데이터베이스에서 제공하는 자동 증가(auto-increment) 열이나 시퀀스(sequence)를 사용합니다. 하지만 때로는 데이터베이스 외부에서 기본 키 값을 생성하고 관리해야 할 필요가 있을 때가 있습니다. 이때 @TableGenerator를 사용할 수 있습니다.
@TableGenerator`를 사용하는 예제는 다음과 같습니다:
@Entity
@Table(name = "employees")
public class Employee {
@Id
@TableGenerator(
name = "employee_id_generator",
table = "id_generators",
pkColumnName = "generator_name",
valueColumnName = "generator_value",
pkColumnValue = "employee_id",
allocationSize = 1
)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "employee_id_generator")
private Long id;
// 나머지 엔티티 필드들
}
위의 코드에서 @TableGenerator 어노테이션을 사용하여 employee_id_generator라는 테이블 기반의 기본 키 생성기를 정의하고, 이 생성기를 @GeneratedValue 어노테이션의 generator 속성에 지정합니다. 이렇게 설정하면 id 필드에 대한 기본 키 값을 employee_id_generator라는 테이블에서 관리하게 됩니다.
@TableGenerator 어노테이션의 주요 속성에 대한 설명은 다음과 같습니다:
- name: 생성기의 이름을 지정합니다.
- table: 생성기 정보를 저장할 테이블의 이름을 지정합니다.
- pkColumnName: 테이블에서 생성기 이름을 저장할 컬럼의 이름을 지정합니다.
- valueColumnName: 테이블에서 생성된 값(value)을 저장할 컬럼의 이름을 지정합니다.
- pkColumnValue: 생성기 이름을 지정합니다. 여러 개의 생성기를 사용할 때 각 생성기에 대한 식별자로 사용됩니다.
- allocationSize: 한 번에 생성할 기본 키 값의 개수를 지정합니다.
@GeneratedValue
@GeneratedValue는 JPA(Java Persistence API)에서 사용되는 어노테이션으로, 엔티티 클래스의 주요 키(primary key) 필드에 대한 자동 생성 전략을 지정할 때 사용됩니다. 주로 데이터베이스 테이블의 기본 키(primary key) 값을 자동으로 생성하는 데 사용됩니다.
@GeneratedValue 어노테이션을 사용하면 다음과 같이 여러 가지 자동 생성 전략을 선택할 수 있습니다:
1. GenerationType.IDENTITY: 이 옵션은 데이터베이스에서 기본 키를 자동으로 생성하는 자동 증가(auto-increment) 열을 사용할 때 주로 선택됩니다. 예를 들어, MySQL에서는 AUTO_INCREMENT와 같이 사용할 수 있습니다.
2. GenerationType.SEQUENCE: 시퀀스(sequence)를 사용하여 기본 키 값을 생성하는 경우에 선택됩니다. 이 옵션은 주로 Oracle과 같은 데이터베이스에서 사용됩니다. 시퀀스는 데이터베이스에서 일련 번호를 생성하는 객체로, 이를 사용하여 기본 키 값을 생성할 수 있습니다.
3. GenerationType.TABLE: 키 생성용 테이블을 사용하여 기본 키 값을 생성하는 경우에 선택됩니다. 이 옵션은 데이터베이스에 키 생성용 테이블을 생성하고 사용하여 기본 키 값을 생성하는 방식입니다.
4. GenerationType.AUTO: JPA 구현 공급자에게 자동 생성 전략을 결정하도록 위임합니다. 이 옵션을 선택하면 JPA 구현 공급자에 따라 자동 생성 전략이 결정됩니다.
예를 들어, 다음과 같이 @GeneratedValue 어노테이션을 사용하여 자동 생성 전략을 설정할 수 있습니다:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
위의 코드에서 strategy 속성을 사용하여 자동 생성 전략을 GenerationType.IDENTITY로 설정했습니다. 이는 데이터베이스의 자동 증가 열을 사용하여 기본 키 값을 생성하겠다는 의미입니다.
hibernate.format_sql
hibernate.format_sql은 Hibernate 프레임워크에서 제공하는 설정 옵션 중 하나입니다. Hibernate는 자바 어플리케이션과 데이터베이스 간의 ORM(객체-관계 매핑)을 지원하는 프레임워크로, SQL 쿼리를 자동으로 생성하고 실행합니다. hibernate.format_sql 설정 옵션은 Hibernate이 생성한 SQL 쿼리를 보기 쉽게 포맷팅하고 로깅하기 위한 용도로 사용됩니다.
일반적으로 개발자들은 hibernate.format_sql 옵션을 true로 설정하여 Hibernate이 생성한 SQL 쿼리를 보기 쉽게 만들 수 있습니다. 이렇게 설정하면 콘솔 출력이나 로그 파일에 Hibernate이 실행한 SQL 쿼리가 포맷팅되어 출력되므로 디버깅 및 성능 최적화 작업을 수행할 때 유용합니다.
hibernate.use_sql_comments
hibernate.use_sql_comments는 Hibernate 설정 옵션 중 하나로, Hibernate이 실행하는 SQL 쿼리에 주석(comment)을 추가하도록 지시하는 옵션입니다. 이 옵션을 사용하면 Hibernate이 생성한 SQL 쿼리에 설명적인 주석을 추가하여, 쿼리가 어떤 작업을 수행하는지에 대한 정보를 포함시킬 수 있습니다.
hibernate.id.new_generator_mappings
hibernate.id.new_generator_mappings는 Hibernate 프레임워크에서 사용되는 설정 옵션 중 하나입니다. 이 옵션은 Hibernate 5.0 버전 이후의 버전부터 도입된 것으로, 기본 키(primary key) 생성 전략과 관련된 이전 버전과의 호환성을 제어하는데 사용됩니다.
기본 키 생성 전략은 Hibernate 엔티티 클래스의 기본 키 필드를 어떻게 생성할지를 결정하는 방법을 지정합니다. Hibernate 5.0 버전 이전에는 다양한 기본 키 생성 전략이 사용되었고, 이러한 전략들은 레거시와의 호환성을 유지하기 위해 XML 파일에서 설정되었습니다. 이전 버전에서는 hbm2ddl.auto 속성을 사용하여 데이터베이스 스키마 생성 및 업데이트를 관리할 때 사용되었습니다.
hibernate.id.new_generator_mappings 옵션을 true로 설정하면 Hibernate은 이전 버전과의 호환성을 무시하고 새로운 기본 키 생성 전략 매핑 방식을 사용하게 됩니다. 이렇게 설정하면 XML 파일에서 설정된 레거시 기본 키 생성 전략이 무시되고, 주로 JPA에서 정의된 @GeneratedValue와 같은 주석 기반의 기본 키 생성 전략이 우선적으로 사용됩니다.
기본적으로 hibernate.id.new_generator_mappings는 Hibernate 5.0 이후의 버전에서는 true로 설정되어 있으며, 새로운 프로젝트에서는 이 설정을 변경할 필요가 없습니다. 하지만 레거시 프로젝트의 경우 호환성 문제가 발생할 수 있으므로 이 설정을 false로 변경하여 기존의 기본 키 생성 전략 매핑 방식을 사용할 수 있습니다.
hibernate.hbm2ddl.auto
hibernate.hbm2ddl.auto는 Hibernate 프레임워크에서 사용되는 설정 옵션 중 하나로, 데이터베이스 스키마 생성과 관련된 옵션입니다. 이 옵션을 사용하면 Hibernate이 어떻게 데이터베이스 스키마를 관리할지를 제어할 수 있습니다.
hibernate.hbm2ddl.auto 설정 옵션은 다양한 값을 가질 수 있으며, 주로 다음과 같은 값들이 사용됩니다:
1. create: 이 옵션을 선택하면 Hibernate은 실행할 때 데이터베이스 스키마를 처음부터 생성합니다. 기존 스키마가 이미 존재한다면 삭제하고 다시 생성합니다. 이는 주로 개발 및 테스트 환경에서 사용됩니다.
2. update: 이 옵션을 선택하면 Hibernate은 실행할 때 기존 스키마를 업데이트합니다. 새로운 테이블, 컬럼 또는 제약 조건을 추가하고, 필요 없는 것은 삭제하지 않습니다. 기존 데이터는 보존됩니다.
3. validate: 이 옵션을 선택하면 Hibernate은 실행할 때 데이터베이스 스키마를 유효성 검사하며, 현재의 엔티티 클래스와 매핑된 테이블이 데이터베이스 스키마와 일치하는지를 확인합니다. 일치하지 않을 경우 예외를 발생시킵니다.
4. create-drop: 이 옵션을 선택하면 Hibernate은 실행할 때 데이터베이스 스키마를 생성하고, 애플리케이션이 종료될 때 다시 스키마를 삭제합니다. 주로 단위 테스트 환경에서 사용됩니다.
5. none: 이 옵션을 선택하면 Hibernate은 데이터베이스 스키마 관리를 하지 않으며, 개발자가 직접 스키마를 생성 및 관리해야 합니다.
예를 들어, Hibernate 설정 파일(XML 또는 JavaConfig)에서 `hibernate.hbm2ddl.auto`를 설정하려면 다음과 같이 설정합니다:
주의해야 할 점은 이 옵션을 사용할 때는 데이터베이스의 중요한 데이터가 손실될 수 있으므로 주의해야 합니다. 일반적으로 개발 및 테스트 환경에서 사용하며, 운영 환경에서는 주의해서 사용해야 합니다.
데이터베이스에서의 시퀀스(Sequence) 및 Hibernate와 함께 사용하는 방법
call next value for hibernate_sequence
주어진 쿼리문 call next value for hibernate_sequence는 데이터베이스에서 시퀀스(Sequence) 값을 생성하는 목적으로 사용되는 SQL 문장입니다. 이 쿼리는 대부분의 데이터베이스 관리 시스템에서 지원하는 것이 아니며, 특정 환경에서만 사용됩니다. 주로 Hibernate와 같은 ORM (Object-Relational Mapping) 라이브러리에서 사용됩니다.
여기에서 각 부분을 자세히 설명해보겠습니다:
1. call: 이 부분은 데이터베이스에서 프로시저나 함수를 호출하는 데 사용되는 키워드입니다. 데이터베이스 시스템에게 특정 작업을 수행하도록 요청합니다.
2. next value for: 이 부분은 시퀀스에서 다음 값을 가져오기 위해 사용되는 명령입니다. 시퀀스는 일련의 고유한 숫자를 생성하는 데 사용되며, 각 번호는 일반적으로 자동으로 증가합니다.
3. hibernate_sequence: 이 부분은 특정 시퀀스의 이름이며, Hibernate나 기타 ORM 라이브러리에서 사용하는 테이블의 기본 키 값을 생성할 때 사용되는 시퀀스의 이름입니다. 이 부분은 데이터베이스 시스템에 따라 다를 수 있으며, 테이블과 연결된 시퀀스의 이름을 나타냅니다.
위 쿼리의 목적은 hibernate_sequence라는 시퀀스에서 다음 값을 가져와서 그 값을 사용하는 것입니다. 이렇게 생성된 값을 일반적으로 테이블의 기본 키(primary key) 필드에 삽입할 때 사용합니다. 이렇게 하면 데이터베이스 시스템이 자동으로 고유한 기본 키 값을 생성하고 관리할 수 있습니다. Hibernate와 같은 ORM 라이브러리는 이러한 시퀀스 값을 생성하고 데이터베이스와 상호작용하는 데 도움을 주는 역할을 합니다.
'JPA' 카테고리의 다른 글
JPA3 (0) | 2023.04.19 |
---|---|
JPA4 (0) | 2023.04.17 |
@DynamicInsert (0) | 2023.04.17 |
JPA2 (0) | 2023.04.13 |
2. Spring Data JPA (0) | 2023.04.12 |