반응형
Jake Seo
제이크서 위키 블로그
Jake Seo
전체 방문자
오늘
어제
  • 분류 전체보기 (715)
    • 일상, 일기 (0)
    • 백준 문제풀이 (1)
    • 릿코드 문제풀이 (2)
    • 알고리즘 이론 (10)
      • 기본 이론 (2)
      • 배열과 문자열 (8)
    • 데이터베이스 (15)
      • Planet Scale (1)
      • MSSQL (9)
      • 디비 기본 개념 (1)
      • SQLite 직접 만들어보기 (4)
    • 보안 (7)
    • 설계 (1)
    • 네트워크 (17)
      • HTTP (9)
      • OSI Layers (5)
    • 회고 (31)
      • 연간 회고 (2)
      • 주간 회고 (29)
    • 인프라 (52)
      • 도커 (12)
      • AWS (9)
      • 용어 (21)
      • 웹 성능 (1)
      • 대규모 서비스를 지탱하는 기술 (9)
    • 깃 (7)
    • 빌드 도구 (7)
      • 메이븐 (6)
      • 그레이들 (0)
    • Java (135)
      • 이펙티브 자바 (73)
      • 자바 API (4)
      • 자바 잡지식 (30)
      • 자바 디자인 패턴 (21)
      • 톰캣 (Tomcat) (7)
    • 프레임워크 (64)
      • next.js (14)
      • 스프링 프레임워크 (28)
      • 토비의 스프링 (6)
      • 스프링 부트 (3)
      • JPA (Java Persistence API) (5)
      • Nest.js (8)
    • 프론트엔드 (48)
      • 다크모드 (1)
      • 노드 패키지 관리 매니저 (3)
      • CSS (19)
      • Web API (11)
      • tailwind-css (1)
      • React (5)
      • React 새 공식문서 요약 (1)
      • HTML (Markup Language) (5)
    • 자바스크립트 (108)
      • 모던 자바스크립트 (31)
      • 개념 (31)
      • 정규표현식 (5)
      • 코드 스니펫 (1)
      • 라이브러리 (6)
      • 인터뷰 (24)
      • 웹개발자를 위한 자바스크립트의 모든 것 (6)
      • 팁 (2)
    • Typescript (49)
    • 리눅스와 유닉스 (10)
    • Computer Science (1)
      • Compiler (1)
    • IDE (3)
      • VSCODE (1)
      • IntelliJ (2)
    • 세미나 & 컨퍼런스 (1)
    • 용어 (개발용어) (16)
      • 함수형 프로그래밍 용어들 (1)
    • ORM (2)
      • Prisma (2)
    • NODEJS (2)
    • cypress (1)
    • 리액트 네이티브 (React Native) (31)
    • 러스트 (Rust) (15)
    • 코틀린 (Kotlin) (4)
      • 자바에서 코틀린으로 (4)
    • 정규표현식 (3)
    • 구글 애널리틱스 (GA) (1)
    • SEO (2)
    • UML (2)
    • 맛탐험 (2)
    • 리팩토링 (1)
    • 서평 (2)
    • 소프트웨어 공학 (18)
      • 테스팅 (16)
      • 개발 프로세스 (1)
    • 교육학 (1)
    • 삶의 지혜, 통찰 (1)
    • Chat GPT (2)
    • 쉘스크립트 (1)
    • 컴파일 (2)
    • Dart (12)
    • 코드팩토리의 플러터 프로그래밍 (4)
    • 플러터 (17)
    • 안드로이드 스튜디오 (1)
    • 윈도우즈 (1)
    • 잡다한 백엔드 지식 (1)
    • 디자인 패턴 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 객체복사
  • 자료구조
  • 슬로우 쿼리
  • 싱글톤 패턴
  • 이펙티브 자바
  • item8
  • 자바스크립트 면접
  • 프로그래머의 뇌
  • 자바
  • bean Validation
  • Next.js
  • 메이븐 페이즈
  • 팩터리 메서드 패턴
  • 자바 검증
  • try-with-resources
  • 스프링 검증
  • 이펙티브 자바 item9
  • Java
  • 자바스크립트
  • 토비의 스프링
  • 싱글턴
  • 플라이웨이트패턴
  • 러스트
  • 자바스크립트 인터뷰
  • item7
  • 자바 디자인패턴
  • 느린 쿼리
  • 빈 검증
  • serverless computing
  • 참조 해제
  • MSSQL
  • next js app
  • 이펙티브자바
  • pnpm
  • 디자인패턴
  • 도커공식문서
  • NEXT JS
  • 메이븐 골
  • rust
  • 추상 팩터리 패턴
  • Javadoc 자바독 자바주석 주석 Comment
  • 메이븐 라이프사이클
  • 알고리즘
  • 싱글톤
  • Pre-rendering
  • 외래키 제약조건
  • 작업기억공간
  • prerendering
  • item9
  • 서버리스 컴퓨팅

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jake Seo

제이크서 위키 블로그

Java/자바 잡지식

Java EE GenerationType 정리

2022. 4. 26. 17:12

GenerationType Enum 개요

기본키 생성 전략의 타입을 정의한다.

Enum 상수 요약

  • AUTO (기본 값): persistence provider 가 특정한 데이터베이스에 따라 적절한 전략을 선택해야 함을 나타낸다.
    • Dialect 에 따라 자동 지정된다고 할 수 있다.
    • AUTO 생성 전략은 데이터베이스에 리소스가 있다고 기대할 수도 있고 혹은 새로운 리소스를 만들어내려 시도할 수도 있다.
    • 스키마 생성을 지원하지 않거나 스키마 리소스를 런타임에 생성할 수 없는 때에 어떻게 리소스를 생성하는지 벤더가 문서를 제공할 수도 있다.
  • IDENTITY: persistence provider 가 데이터베이스 identity 컬럼을 사용하여 엔티티에 반드시 기본 키를 할당해야 함을 나타낸다.
    • 보통 데이터베이스에 키 설정을 위임하는 것이다.
  • SEQUENCE: persistence provider 가 데이터베이스 sequence 를 사용하여 엔티티에 반드시 기본 키를 할당해야 함을 나타낸다.
    • 데이터베이스의 시퀀스 오브젝트를 이용하는 것이다.
  • TABLE: persistence provider 가 유니크함을 보장하기 위해 기재된 테이블을 사용하여 엔티티에 반드시 기본키를 할당해야 함을 나타낸다.
    • 키 생성용 테이블을 사용하는 것이다.

AUTO 전략 세부 분석

  • AUTO 생성 전략을 해석하는 일은 전적으로 persistence provider 에 달려있다.
  • 가장 처음으로 하는 일은 식별자(identifier) 타입이 UUID 인지 확인하고 UUID 라면 UUID identifier를 적용하는 것이다.
  • 만일, 식별자 타입이 숫자(ex. Long, Integer)라면, IdGeneratorStrategyInterpreter 를 적용한다.

IdGeneratorStrategyInterpreter 의 구현체

  • FallbackInterpreter: 하이버네이트 5.0 부터 이 전략이 기본 전략이다. 이 전략에서 AUTO 는 SequenceStyleGenerator 로 해석된다. 만일, DB 에서 SEQUENCE 를 제공한다면 SEQUENCE 생성기가 사용되고, 지원하지 않는다면 TABLE 생성기가 대신 사용될 것이다.

  • LegacyFallbackInterpreter: 하이버네이트 5.0 이전에 사용되던 레거시 매커니즘이다. native 생성기를 사용하는데, 이는 NativeIdentifierGeneratorStrategy 를 따른다.

Sequence 사용 세부 분석

데이터베이스 시퀀스 기반 식별자 값 생성 구현을 위해, 하이버네이트는 org.hibernate.id.enhanced.SequenceStyleGenerator 식별자 생성기를 이용한다. SequenceStyleGenerator 는 테이블을 뒷단에 두어 시퀀스를 지원하지 않는 데이터베이스에 대해서도 동작이 가능하다. 이러한 점은 하이버네이트에게 여러 데이터베이스 사이에서의 뛰어난 이동성을 준다. (SEQUENCE 와 IDENTITY 중 선택하라는 것과 대비된다.) 이 때 사용되는 백업 스토리지는 사용자에게 완전히 투명하다.

이 생성기를 설정하기 위해 선호되는 방식은 JPA 에서 정의한 @SequenceGenerator 애노테이션을 사용하는 것이다. 시퀀스 생성을 요청하는 가장 간단한 형태이다. 하이버네이트는 이름이 정해지지 않은 시퀀스 정의에 대해서는 단일로 동작하며 암묵적으로 이름이 정해진 시퀀스(hibernate-sequence) 를 사용할 것이다.

이름이 없는 시퀀스

@Entity(name = "Product")
public static class Product {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE
    )
    private Long id;

    @Column(name = "product_name")
    private String name;
    //Getters and setters are omitted for brevity
}

@SequenceGenerator 애노테이션을 이용해 직접 데이터베이스 시퀀스 네임을 줄 수도 있다.

이름이 있는 시퀀스

@Entity(name = "Product")
public static class Product {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "sequence-generator"
    )
    @SequenceGenerator(
        name = "sequence-generator",
        sequenceName = "product_sequence"
    )
    private Long id;

    @Column(name = "product_name")
    private String name;
}

@SequenceGenerator 애노테이션을 이용해 시퀀스 이름을 직접 설정하는 방법이다.

설정이 있는 시퀀스

@Entity(name = "Product")
public static class Product {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "sequence-generator"
    )
    @SequenceGenerator(
        name = "sequence-generator",
        sequenceName = "product_sequence",
        allocationSize = 5
    )
    private Long id;

    @Column(name = "product_name")
    private String name;
    //Getters and setters are omitted for brevity
}

IDENTITY 컬럼 이용하기

하이버네이트는 IDENTITY 컬럼을 기반으로 하는 ID 값 생성을 구현하기 위해, 테이블에 INSERT 를 통해 ID 가 생성되어야 하는 org.hibernate.id.IdentityGenerator 아이디 생성기를 사용한다. 하이버네이트는 INSERT 로 생성된 값을 가져오는 3가지 방법을 이해한다.

  • 하이버네이트가 JDBC 환경에서 java.sql.Statement#getGeneratedKeys 를 지원한다는 것을 인지하면, IDENTITY 에 의해 생성된 키를 추출하기 위해 이를 사용할 것이다.
  • Dialect#supportsInsertSelectIdentity 가 true 라면, 하이버네이트는 Dialect 에 맞는 INSERT+SELECT 문 문법을 사용할 것이다.
  • 위 두가지가 모두 안 된다면, Dialect#getIdentitySelectString 에 의해 가리켜지는 가장 최근에 삽입된 IDENTITY 값을 요청할 것이다.

이 방법은 엔티티 row 가 반드시 ID 값이 알려지기 전에 물리적으로 insert 된다는 점에서 runtime behavior 를 부과한다는 것을 알아두는 것이 중요하다. 확장된 영속성 컨텍스트를 망칠 수 있다. 런타임 불일치성 때문에, 하이버네이트는 다른 형태의 ID 값 생성을 사용하기를 제안한다.

또 하나 알아둬야 할 중요한 것은 하이버네이트는 IDENTITY 생성을 사용하는 엔티티의 INSERT 에 대해 JDBC batching 을 할 수 없다. 이 중요성은 애플리케이션의 세부적인 유즈 케이스에 따라 달라진다. 만일 애플리케이션에서 IDENTITY 생성을 사용하는 엔티티를 많이 생성하지 않는다면, 배치가 그렇게 도움되지는 않을 것이므로 큰 영향이 없을 수 있다.

Table ID 생성기 이용하기

많은 수의 엔티티에 대해 여러 개의 명명된 값 세그먼트들을 가지고 있을 수 있는 테이블을 정의하는 org.hibernate.id.enhanced.TableGenerator 를 기반으로하는 테이블 기반 ID 생성기를 사용할 수 있다.

주어진 테이블 생성기 (ex. hibernate_sequences 같은) 테이블이 여러 개의 ID 생성기 값들의 세그먼트를 가지고 있을 수 있다는 사실을 기반으로 한다.

@Entity(name = "Product")
public static class Product {
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE
    )
    private Long id;

    @Column(name = "product_name")
    private String name;
    //Getters and setters are omitted for brevity
}
create table hibernate_sequences (
    sequence_name varchar2(255 char) not null,
    next_val number(19,0),
    primary key (sequence_name)
)

만일 어떠한 테이블 이름도 주어지지 않는다면, hibernate_sequences 라는 암묵적인 이름을 따를 것이다.

추가적으로, javax.persistence.TableGenerator#pkColumnValue 도 명세되어 있지 않기 때문에, 하이버네이트는 hibernate_sequences 테이블에서도 기본 세그먼트(sequence_name='default')를 사용할 것이다.

@TableGenerator 애노테이션을 사용해 테이블 ID 생성기 세부사항을 설정할 수도 있다.

@Entity(name = "Product")
public static class Product {

    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = "table-generator"
    )
    @TableGenerator(
        name =  "table-generator",
        table = "table_identifier",
        pkColumnName = "table_name",
        valueColumnName = "product_id",
        allocationSize = 5 // 최적화를 위해 사용된다.
    )
    private Long id;

    @Column(name = "product_name")
    private String name;

    //Getters and setters are omitted for brevity
}

allocationSize 는 식별자 값을 한 번에 몇개씩 생성할지에 대한 사이즈이다.

create table table_identifier (
    table_name varchar2(255 char) not null,
    product_id number(19,0),
    primary key (table_name)
)

여기서 만일 3 개의 Product 엔티티를 추가한다면, 하이버네이트는 아래의 구문들을 만들어낼 것이다.

for ( long i = 1; i <= 3; i++ ) {
    Product product = new Product();
    product.setName( String.format( "Product %d", i ) );
    entityManager.persist( product );
}

Product 데이터 3개를 추가하는 For 문을 수행한다.

select
    tbl.product_id
from
    table_identifier tbl
where
    tbl.table_name = ? -- Product
for update

-- binding parameter [1] - [Product]

데이터를 사용하려 table_identifier 테이블에서 table_name 이 Product 이며, product_id 컬럼에 락을 건다. 락을 걸면, 다른 세션에서 접근할 수 없다. for update 관련 참고

insert
into
    table_identifier
    (table_name, product_id)
values
    (?, ?) -- (Product, 1)

-- binding parameter [1] - [Product]
-- binding parameter [2] - [1]

table_identifier 테이블에 table_name 이 Product 이며, product_id 가 1 인 데이터를 삽입한다.

update
    table_identifier
set
    product_id= ?
where
    product_id= ?
    and table_name= ?

-- binding parameter [1] - [6]
-- binding parameter [2] - [1]
-- binding parameter [3] - [Product]
select
    tbl.product_id
from
    table_identifier tbl
where
    tbl.table_name = ? for update
-- binding parameter [1] - [Product]
update
    table_identifier
set
    product_id= ?
where
    product_id= ?
    and table_name= ?

-- binding parameter [1] - [11]
-- binding parameter [2] - [6]
-- binding parameter [3] - [Product]
insert
into
    Product
    (product_name, id)
values
    (?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 1]
-- binding parameter [2] as [BIGINT]  - [1]
insert
into
    Product
    (product_name, id)
values
    (?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 2]
-- binding parameter [2] as [BIGINT]  - [2]
insert
into
    Product
    (product_name, id)
values
    (?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 3]
-- binding parameter [2] as [BIGINT]  - [3]

UUID 생성기 이용하기

UUID 타입에 org.hibernate.id.UUIDGenerator 를 통해 UUID 생성을 지원한다.

기본 전략은 IETF RFC 4122 를 따르는 버전 4 (랜덤) 전략이다. 하이버네이트에서는 RFC 4122 버전 1 (시간 기반) 전략도 대안으로 제공한다.

@Entity(name = "Book")
public static class Book {

    @Id
    @GeneratedValue
    private UUID id;

    private String title;

    private String author;

    //Getters and setters are omitted for brevity
}

버전 1을 쓰려면 @GenericGenerator 애너테이션을 정의해야 한다. org.hibernate.id.uuid.CustomVersionOneStrategy 를 통해 아래와 같이 설정 가능하다.

@Entity(name = "Book")
public static class Book {

    @Id
    @GeneratedValue( generator = "custom-uuid" )
    @GenericGenerator(
        name = "custom-uuid",
        strategy = "org.hibernate.id.UUIDGenerator",
        parameters = {
            @Parameter(
                name = "uuid_gen_strategy_class",
                value = "org.hibernate.id.uuid.CustomVersionOneStrategy"
            )
        }
    )
    private UUID id;

    private String title;

    private String author;

    //Getters and setters are omitted for brevity
}

옵티마이저

DB 구조로부터 식별자 값을 각각 얻는 대부분의 하이버네이트 생성기는 이식 가능한 옵티마이저를 지원한다. 옵티마이저는 식별자를 생성하기 위해 DB 와 연결하는 부분을 최소화해준다.

None

아무런 옵티마이저도 적용하지 않는다. 매번 DB 와 통신한다.

Pooled-lo

create sequence m_sequence start with 1 increment by 20 와 같은 방식으로 적용 가능하다. 20 개의 사용 가능한 식별자를 미리 만들어놓는 것이다.

처음에 id 1을 얻어오고, 20까지 사용할 수 있음을 알 수 있다.

다음 호출에는 아이디 21이 결과로 나올 것이다. 이 때는 물론 21-40이 유효한 범위일 것이다.

"pooled-lo" 에서 "lo" 의 의미는 "pool low end" 일 것이다.

Pooled

Pooled-lo 와 흡사한데, 숫자를 위에서부터 받는다.

hilo, legacy-hilo

pool 을 만드는 커스텀 알고리즘을 정의한다. 사용은 권장되지 않는다.

애플리케이션은 자신만의 옵티마이저 전략을 사용할 수도 있다. org.hibernate.id.enhanced.Optimizer 에 정의되어 있다.

@GenericGenerator 이용하기

@GenericGenerator 는 어떤 하이버네이트의 org.hibernate.id.IdentifierGenerator 구현과도 통합을 제공한다. 위에 언급된 ID 생성 전략과도 통합될 수 있다.

아래의 코드는 SEQUENCE 전략에 Pooled-lo 최적화를 사용했다.

@Entity(name = "Product")
public static class Product {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "product_generator"
    )
    @GenericGenerator(
        name = "product_generator",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
            @Parameter(name = "sequence_name", value = "product_sequence"),
            @Parameter(name = "initial_value", value = "1"),
            @Parameter(name = "increment_size", value = "3"),
            @Parameter(name = "optimizer", value = "pooled-lo")
        }
    )
    private Long id;

    @Column(name = "p_name")
    private String name;

    @Column(name = "p_number")
    private String number;
    //Getters and setters are omitted for brevity
}

이제 5개의 Product 엔티티를 저장한다면, 매 3번마다 Persistence Context 를 flush 할 것이다. 아래 코드는 예시이다.

for ( long i = 1; i <= 5; i++ ) {
    if(i % 3 == 0) {
        entityManager.flush();
    }
    Product product = new Product();
    product.setName( String.format( "Product %d", i ) );
    product.setNumber( String.format( "P_100_%d", i ) );
    entityManager.persist( product );
}
CALL NEXT VALUE FOR product_sequence

INSERT INTO Product (p_name, p_number, id)
VALUES (?, ?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 1]
-- binding parameter [2] as [VARCHAR] - [P_100_1]
-- binding parameter [3] as [BIGINT]  - [1]

INSERT INTO Product (p_name, p_number, id)
VALUES (?, ?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 2]
-- binding parameter [2] as [VARCHAR] - [P_100_2]
-- binding parameter [3] as [BIGINT]  - [2]

CALL NEXT VALUE FOR product_sequence

INSERT INTO Product (p_name, p_number, id)
VALUES (?, ?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 3]
-- binding parameter [2] as [VARCHAR] - [P_100_3]
-- binding parameter [3] as [BIGINT]  - [3]

INSERT INTO Product (p_name, p_number, id)
VALUES (?, ?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 4]
-- binding parameter [2] as [VARCHAR] - [P_100_4]
-- binding parameter [3] as [BIGINT]  - [4]

INSERT INTO Product (p_name, p_number, id)
VALUES (?, ?, ?)

-- binding parameter [1] as [VARCHAR] - [Product 5]
-- binding parameter [2] as [VARCHAR] - [P_100_5]
-- binding parameter [3] as [BIGINT]  - [5]

시작할 때 그리고 3번째 데이터를 추가할 때 CALL NEXT VALUE FOR product_sequence 가 일어난다. 6 번째 데이터를 추가한다면 또 CALL NEXT VALUE FOR product_sequence 가 일어날 것이다. 이러한 최적화가 DB 까지 오가는 시간을 줄여준다.

Derived Identifiers

JPA 2.0 에서 지원한다. many-to-one 혹은 one-to-one 관계로부터 ID 를 빌려온다.

@Entity(name = "Person")
public static class Person  {

    @Id
    private Long id;

    @NaturalId
    private String registrationNumber;

    public Person() {}

    public Person(String registrationNumber) {
        this.registrationNumber = registrationNumber;
    }

    //Getters and setters are omitted for brevity
}

@Entity(name = "PersonDetails")
public static class PersonDetails  {

    @Id
    private Long id;

    private String nickName;

    @OneToOne
    @MapsId
    private Person person;

    //Getters and setters are omitted for brevity
}

위의 예에서 PersonDetails 엔티티는 엔티티 식별자와 Person 엔티티와의 one-to-one 관계에 대해 id 컬럼을 사용한다. PersonDetails 엔티티 ID의 값은 부모 Person 엔티티의 ID 로 부터 "derived" 된다.

doInJPA(this::entityManagerFactory, entityManager -> {
    Person person = new Person( "ABC-123" );
    person.setId( 1L );
    entityManager.persist( person );

    PersonDetails personDetails = new PersonDetails();
    personDetails.setNickName( "John Doe" );
    personDetails.setPerson( person );

    entityManager.persist( personDetails );
});

doInJPA(this::entityManagerFactory, entityManager -> {
    PersonDetails personDetails = entityManager.find( PersonDetails.class, 1L );

    assertEquals("John Doe", personDetails.getNickName());
});

@MapsId 애노테이션은 @EmbeddedId ID 로 된 컬럼도 참조할 수 있다. 이전 예제는 @PrimaryKeyJoinColumn 을 통해서도 매핑될 수 있다.

@Entity(name = "Person")
public static class Person  {
    @Id
    private Long id;

    @NaturalId
    private String registrationNumber;

    public Person() {}

    public Person(String registrationNumber) {
        this.registrationNumber = registrationNumber;
    }
    //Getters and setters are omitted for brevity
}

@Entity(name = "PersonDetails")
public static class PersonDetails  {
    @Id
    private Long id;

    private String nickName;

    @OneToOne
    @PrimaryKeyJoinColumn
    private Person person;

    public void setPerson(Person person) {
        this.person = person;
        this.id = person.getId();
    }
    //Other getters and setters are omitted for brevity
}

@MapsId 와 다르게, 애플리케이션 개발자는 ID 와 many-to-one 혹은 one-to-one1 관계가 싱크가 맞는다는 것을 보장할 책임이 있다. PersonDetails#setPerson 메서드에서 이를 처리하고 있다.

@RowId

@RowId 애노테이션을 붙이고, ROWID(ex. 오라클) 에 의해 기록을 가져오는 것을 데이터베이스가 지원하면, 하이버네이트는 CRUD 연산에 대해 ROWID 의사 컬럼을 사용할 수 있다.

Product product = entityManager.find( Product.class, 1L );

product.setName( "Smart phone" );
SELECT
    p.id as id1_0_0_,
    p."name" as name2_0_0_,
    p."number" as number3_0_0_,
    p.ROWID as rowid_0_
FROM
    Product p
WHERE
    p.id = ?

-- binding parameter [1] as [BIGINT] - [1]

-- extracted value ([name2_0_0_] : [VARCHAR]) - [Mobile phone]
-- extracted value ([number3_0_0_] : [VARCHAR]) - [123-456-7890]
-- extracted ROWID value: AAAwkBAAEAAACP3AAA

UPDATE
    Product
SET
    "name" = ?,
    "number" = ?
WHERE
    ROWID = ?

-- binding parameter [1] as [VARCHAR] - [Smart phone]
-- binding parameter [2] as [VARCHAR] - [123-456-7890]
-- binding parameter [3] as ROWID     - [AAAwkBAAEAAACP3AAA]

레퍼런스

  • java EE 스펙 문서
  • 하이버네이트 공식문서 2.6.7 섹션 이후
반응형
저작자표시 (새창열림)

'Java > 자바 잡지식' 카테고리의 다른 글

DTO (Data Transfer Object) 란?  (0) 2022.04.27
Java EE 빈 검증 (Bean Validation)  (0) 2022.04.27
Java EE @GeneratedValue 공식문서 번역 정리  (0) 2022.04.26
Lombok 을 사용할 때 주의해야 하는 점들 정리  (0) 2022.04.23
스프링 @Bean 애노테이션 정리  (0) 2022.04.23
    'Java/자바 잡지식' 카테고리의 다른 글
    • DTO (Data Transfer Object) 란?
    • Java EE 빈 검증 (Bean Validation)
    • Java EE @GeneratedValue 공식문서 번역 정리
    • Lombok 을 사용할 때 주의해야 하는 점들 정리
    Jake Seo
    Jake Seo
    ✔ 잘 보셨다면 광고 한번 클릭해주시면 큰 힘이 됩니다. ✔ 댓글로 틀린 부분을 지적해주시면 기분 나빠하지 않고 수정합니다. ✔ 많은 퇴고를 거친 글이 좋은 글이 된다고 생각합니다. ✔ 간결하고 명료하게 사람들을 이해 시키는 것을 목표로 합니다.

    티스토리툴바