Skip to content
Mambo edited this page Sep 11, 2024 · 12 revisions

오랫동안 사용하지 않았던 JPA 사용해보기!

JPA 관련 애플리케이션 속성 설정

spring:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        boot.allow_jdbc_metadata_access: false
    open-in-view: false
    database-platform: org.hibernate.dialect.PostgreSQLDialect
  datasource:
    url: jdbc:postgresql://[hostname]:5432/[database]
    hikari:
      jdbc-url: ${spring.datasource.url}
    username: [user]
    password: [password]

Hibernate Entity Manager 직접 호출하기

테이블을 만들지 않고 간단한 쿼리를 호출하고 싶을때 (예, 데이터베이스 버전 조회)

@PersistenceContext
EntityManager entityManager;

String version = entityManager.createQuery("SELECT version()", String.class).getSingleResult();

단일 컬럼을 매핑해서 가져올 방법은 없다!

사용자에 대한 테넌트 아이디(u_grp_id)를 함께 가져오고 싶을 때 참조 테이블에 대한 조인 패치를 위해서는 엔터티로 관리되어야함

@Data
@Entity
@Table(name = "\"user\"")
public class UserEntity {
    @Id
    @Column(name = "u_id")
    private String uId;
    private String id;
    private String name;
    private String language;
    private String timeZone;
    private String type;
    private boolean del;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "u_id", referencedColumnName = "u_id", insertable = false, updatable = false)
    private UserRel userRel;

    public String getUGrpId() {
        return userRel == null ? null : userRel.getUGrpId();
    }
}

@Data
@IdClass(UserRel.ID.class)
@Entity
@Table(name = "user_rel")
public class UserRel {

    @Id
    @Column(name = "u_id")
    private String uId;

    @Id
    @Column(name = "u_grp_id")
    private String uGrpId;

    @Data
    public static class ID implements Serializable {
        private String uGrpId;
        private String uId;
    }
}

Enum 과 Field 간 변환

org.springframework.dao.DataIntegrityViolationException: Could not extract column [7] from JDBC ResultSet [Bad value for type byte : SYSTEM] [n/a]; SQL [n/a]
...
Caused by: org.hibernate.exception.DataException: Could not extract column [7] from JDBC ResultSet [Bad value for type byte : SYSTEM] [n/a]
...
Caused by: org.postgresql.util.PSQLException: Bad value for type byte : SYSTEM

@Enumerated(EnumType.STRING) 또는 JPA Attribute Converter 로 자바 Enum 을 DB 컬럼과 매핑할 수 있다.

  • @Enumerated(EnumType.STRING): Enum 과 데이터베이스에 저장되는 결과가 동일할 때
  • Attribue Converter: Enum 과 데이터베이스에 저장되는 값이 일치하지 않는 경우
@Enumerated(EnumType.STRING)
@JdbcType(PostgreSQLEnumJdbcType.class)
private UserType type;

JSON 데이터 처리는?...

public class UserEntity {
    @JdbcTypeCode(SqlTypes.JSON)
    private Metadata metadata;

    @Data
    public static class Metadata {
        private String status;
        @JsonAlias({"alarm_interval"})
        private String alarmInterval;
    }
}

PostgreSQL의 PL/pgSQL 함수를 사용할 수 있는 방법

EntityManager 또는 JdbcTemplate 로 프로시저 콜 호출하기...

N+1 문제

신입 개발자 이력서에서 쉽게 볼 수 있던... JOIN 을 수행하지 않고 조회 목록에 대한 개수 만큼 개별 조회를 수행하는 과정, JPQL 로 Fetch Join을 수행해야 한다?

Hibernate: select ue1_0.u_id,ue1_0.created,ue1_0.del,ue1_0.id,ue1_0.language,ue1_0.last_login_time,ue1_0.name,ue1_0.time_zone,ue1_0.type from "user" ue1_0 offset ? rows fetch first ? rows only
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select ur1_0.u_grp_id,ur1_0.u_id from user_rel ur1_0 where ur1_0.u_id=?
Hibernate: select count(ue1_0.u_id) from "user" ue1_0
@Transactional(readOnly = true)
public interface UserEntityRepository extends JpaRepository<UserEntity, String> {
    @Query("SELECT u FROM UserEntity u join fetch u.userRel")
    Page<UserEntity> findAll(Pageable pageable);
}
Hibernate: select ue1_0.u_id,ue1_0.created,ue1_0.del,ue1_0.id,ue1_0.language,ue1_0.last_login_time,ue1_0.name,ue1_0.time_zone,ue1_0.type,ur1_0.u_grp_id,ur1_0.u_id from "user" ue1_0 join user_rel ur1_0 on ur1_0.u_id=ue1_0.u_id fetch first ? rows only
Hibernate: select count(ue1_0.u_id) from "user" ue1_0 join user_rel ur1_0 on ur1_0.u_id=ue1_0.u_id

Instant and OffsetDateTime

@JdbcType(OffsetDateTimeJdbcType.class)
private OffsetDateTime createdAt;

@JdbcType(InstantJdbcType.class)
private Instant lastLoginTime;
  • Timestamp with timezone 으로 만들어지며 long 은 Timestamp 컬럼이 된다.

Clone this wiki locally