JPA와 컬럼 순서
최근, ReadWe 프로젝트를 시작했다. 가장 먼저 Sign-up API를 설계하고 테스트해 보았는데, 엔티티 클래스에서 선언한 필드들이 정작 DB에 생성된 테이블을 보니 컬럼 순서가 뒤죽박죽이었다.
이유는 간단했다. JPA는 기본적으로 자바 리플렉션을 통해 엔티티 클래스의 필드 정보를 읽어온다. 그런데 리플렉션으로 필드 정보를 읽을 때는 자바 소스 코드에 작성한 순서가 보장되지 않는다. 쉽게 말해 아래와 같이 코드를 작성해도 DB에 생성된 테이블에서는 순서 상관없이 나타날 수 있다.
@Entity
@Table(name = "User")
public class User {
private String userId;
private String email;
private String password;
private String name;
private String colorCode;
private LocalDateTime createdAt;
}
+------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+-------+
| color_code | varchar(7) | YES | | NULL | |
| created_at | datetime(6) | YES | | NULL | |
| user_id | varchar(36) | NO | PRI | NULL | |
| name | varchar(50) | YES | | NULL | |
| email | varchar(100) | YES | | NULL | |
| password | varchar(100) | YES | | NULL | |
+------------+--------------+------+-----+---------+-------+
컬럼 순서를 보장하고 싶다면
DDL 스크립트를 사용해 직접 제어하자. 작성한 필드 순서를 유지하고 싶다면 schema.sql 파일로 테이블을 생성하면 된다. (spring.jpa.hibernate.ddl-auto=none)
컬럼 순서에 의존하지 말자
어쨌든 JPA는 컬럼 이름을 기준으로 매핑한다. 컬럼 순서를 원하는 대로 고정하였을 때 이점은 보기 좋다는 것뿐이다. 실제 앱 기능상 컬럼 순서가 영향을 미치는 건 하나도 없으니 컬럼 순서를 강박적으로 맞추는 것은 바보 같은 짓이다. (지금이야 몇 개 안 되는 컬럼이지만, 나중에 수십 수백 개의 컬럼으로 증가한다면 어떻게 관리할 수 있겠는가.)
결국 가장 중요한 것은 순서 따위가 아닌, '얼마나 의미 있는 필드 정의를 하였는가', '매핑 정확성은 어떠한가'와 같은 것들이다.
P.S. 자꾸 사소한 거에 신경쓰다 보니 개발 속도가 늦어지는 것 같다. 그래도 후회는 하지 말아야지!
더보기
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Column {
/**
* (Optional) The name of the column. Defaults to
* the property or field name.
*/
String name() default "";
/**
* (Optional) Whether the column is a unique key. This is a
* shortcut for the <code>UniqueConstraint</code> annotation at the table
* level and is useful for when the unique key constraint
* corresponds to only a single column. This constraint applies
* in addition to any constraint entailed by primary key mapping and
* to constraints specified at the table level.
*/
boolean unique() default false;
/**
* (Optional) Whether the database column is nullable.
*/
boolean nullable() default true;
/**
* (Optional) Whether the column is included in SQL INSERT
* statements generated by the persistence provider.
*/
boolean insertable() default true;
/**
* (Optional) Whether the column is included in SQL UPDATE
* statements generated by the persistence provider.
*/
boolean updatable() default true;
/**
* (Optional) The SQL fragment that is used when
* generating the DDL for the column.
* <p> Defaults to the generated SQL to create a
* column of the inferred type.
*/
String columnDefinition() default "";
/**
* (Optional) The name of the table that contains the column.
* If absent the column is assumed to be in the primary table.
*/
String table() default "";
/**
* (Optional) The column length. (Applies only if a
* string-valued column is used.)
*/
int length() default 255;
/**
* (Optional) The precision for a decimal (exact numeric)
* column. (Applies only if a decimal column is used.)
* Value must be set by developer if used when generating
* the DDL for the column.
*/
int precision() default 0;
/**
* (Optional) The scale for a decimal (exact numeric) column.
* (Applies only if a decimal column is used.)
*/
int scale() default 0;
}
컬럼 얘기가 나온 김에 JPA에서 @Column 생략 시 디폴트 값이 뭔지 궁금해서 복사해 왔다.
'MAIN > Java & Spring' 카테고리의 다른 글
자료구조 힙(Heap), 자바에 TCO가 없는 이유는? (3) | 2025.06.27 |
---|---|
JPA 프로젝트에서 타임스탬프 자동화를 위한 세 가지 전략 (1) | 2025.06.10 |
Spring Boot 드라이버 인식 오류 (driver-class-name) (2) | 2025.05.23 |
Spring Boot에서 JPA로 Docker MySQL 연동하기 (2) | 2025.05.22 |
BFS 그래프의 표현 방식: List<ArrayList<Integer>>, List<int[]> (0) | 2025.05.21 |