@Column 애너테이션은 JPA 엔티티 필드를 데이터베이스 컬럼과 매핑할 때 사용하는 애너테이션입니다. 기본적으로 엔티티의 필드 이름과 동일한 컬럼 이름으로 매핑되지만, 세부적인 설정을 통해 컬럼 속성을 지정할 수 있습니다.
1. @Column의 주요 속성
속성 | 설명 | 기본값 |
name | 매핑할 데이터베이스 컬럼 이름 | 필드 이름과 동일 |
nullable | 컬럼에 NULL 값 허용 여부 | true |
unique | 해당 컬럼에 유니크 제약 조건을 설정 | false |
length | 문자열 컬럼의 길이 설정 (VARCHAR와 CHAR에만 적용) | 255 |
precision | BigDecimal 타입에서 전체 자리수 설정 (숫자형에만 적용) | 0 |
scale | BigDecimal 타입에서 소수점 자리수 설정 | 0 |
insertable | INSERT 쿼리에 포함 여부 | true |
updatable | UPDATE 쿼리에 포함 여부 | true |
columnDefinition | DDL 생성 시 컬럼의 데이터 타입이나 제약 조건을 직접 명시 | 자동 생성된 값 |
table | 해당 컬럼이 매핑될 테이블 이름 (멀티 테이블 매핑에 사용) | 기본 테이블 이름 |
2. 주요 속성 사용 예제
2.1 name
컬럼 이름을 엔티티 필드 이름과 다르게 설정:
@Column(name = "user_name")
private String name;
- 필드 name은 데이터베이스 컬럼 user_name으로 매핑됩니다.
2.2 nullable
NULL 허용 여부 설정:
@Column(nullable = false)
private String email;
- nullable = false는 DDL 생성 시 NOT NULL 제약 조건을 추가합니다.
2.3 unique
유니크 제약 조건 설정:
@Column(unique = true)
private String username;
- 주의: unique = true는 DDL에서 유니크 제약 조건을 생성하지만, 여러 컬럼을 조합한 유니크 제약 조건은 @Table의 uniqueConstraints를 사용해야 합니다.
2.4 length
문자열 필드 길이 제한:
@Column(length = 50)
private String firstName;
- length = 50은 DDL에서 해당 컬럼의 길이를 VARCHAR(50)으로 생성합니다.
2.5 precision과 scale
BigDecimal 또는 숫자형 필드의 전체 자리수와 소수점 자리수 설정:
@Column(precision = 10, scale = 2)
private BigDecimal price;
- precision = 10, scale = 2는 최대 자리수 10, 소수점 아래 2자리로 제한합니다.
- 예를 들어, 12345678.91은 허용되지만 123456789.91은 허용되지 않습니다.
2.6 insertable와 updatable
컬럼이 INSERT 또는 UPDATE 쿼리에 포함될지 여부 설정:
@Column(insertable = false, updatable = false)
private String createdAt;
- insertable = false: INSERT 쿼리에서 제외.
- updatable = false: UPDATE 쿼리에서 제외.
2.7 columnDefinition
DDL 생성 시 데이터 타입과 제약 조건 명시:
@Column(columnDefinition = "TEXT NOT NULL")
private String description;
- Hibernate가 기본으로 생성하는 타입 대신 명시적으로 타입과 제약 조건을 지정합니다.
2.8 table
컬럼이 특정 테이블에 매핑되도록 설정:
@Column(table = "user_details")
private String address;
- 엔티티가 여러 테이블로 매핑될 때 사용합니다.
3. 사용 시 주의할 점
- DDL 자동 생성과 스키마 관리
- @Column은 Hibernate가 DDL을 자동 생성할 때만 유효합니다.
- 운영 환경에서는 DDL 자동 생성을 비활성화(ddl-auto=none)하고, 스키마 관리 도구(Flyway, Liquibase)를 사용하는 것이 안전합니다.
- nullable과 애플리케이션 유효성 검사
- nullable = false는 데이터베이스 제약 조건만 추가하며, 애플리케이션의 입력값 유효성 검사는 별도로 구현해야 합니다.
- Spring Validation을 활용해 @NotNull 같은 애너테이션을 함께 사용하세요.
- 유니크 제약 조건
- 단일 컬럼의 유니크 제약 조건은 unique = true로 설정 가능하지만, 다중 컬럼 조합 유니크 제약 조건은 @Table의 uniqueConstraints를 사용해야 합니다:
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"username", "email"}))
4. columnDefinition 사용 주의
- 데이터베이스에 종속적인 정의를 포함하면 다른 DBMS로 마이그레이션할 때 문제가 발생할 수 있습니다.
- 가능한 Hibernate의 기본 매핑을 사용하는 것이 좋습니다.
5. precision과 scale
- 숫자 타입 매핑 시, 데이터베이스의 기본 동작이 상이할 수 있으므로 직접 테스트 후 사용하는 것이 좋습니다.
6. 데이터 크기와 인덱스 주의
- 길거나 큰 데이터(예: TEXT, BLOB)는 인덱스 생성에 제약이 있을 수 있으므로 적절히 설계해야 합니다.
4. 실무 적용 예제
User.java
package com.example.jpa.domain;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.antlr.v4.runtime.misc.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_name", nullable = false, length = 50, unique = true)
@NotNull
private String userName;
@Column(nullable = false)
private String email;
@Column(precision = 10, scale = 2)
private BigDecimal balance;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private LocalDateTime createdAt;
@Transient
private String tempData; // 매핑하지 않을 필드
}
UserController
package com.example.jpa.controller;
import com.example.jpa.domain.User;
import com.example.jpa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@PostMapping
public User createUser(@RequestBody User user) {
return userRepository.save(user);
}
@GetMapping
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
UserRepository
package com.example.jpa.repository;
import com.example.jpa.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
- API 테스트
POST <http://localhost:8080/users>
Content-Type: application/json
{
"username": "testuser",
"email": "test@example.com",
"balance": 1000.50
}
Snake Case와 Camel Case 규칙 주의할 점
- Snake Case: 단어 사이를 _로 구분하며, 모든 문자를 소문자로 작성합니다.
- 예: first_name, created_at
- SQL과 친화적이며 가독성이 좋습니다.
- Camel Case: 첫 단어는 소문자, 이후 단어는 첫 글자를 대문자로 작성합니다.
- 예: firstName, createdAt
- Java에서 변수명, 필드명을 작성할 때 일반적으로 사용합니다.
SQL 표준과의 호환성
- SQL은 대소문자를 구분하지 않는 경우가 많지만, 일부 DBMS(MariaDB, MySQL 등)는 설정에 따라 대소문자를 구분합니다.
- Snake Case는 모든 문자가 소문자이므로 SQL 표준과 잘 호환됩니다.
- Camel Case를 사용할 경우 데이터베이스에서 자동으로 소문자로 변환될 수 있으므로 주의가 필요합니다.
JPA와의 매핑 문제
- JPA는 엔티티의 필드 이름(보통 Camel Case)을 기본적으로 컬럼 이름으로 매핑합니다.
- 데이터베이스 컬럼명이 Snake Case일 경우 자동 매핑이 실패할 수 있습니다.
- 예: 필드 firstName → 컬럼 firstName(Camel Case)로 매핑 시 문제 발생.
- 데이터베이스 컬럼은 first_name(Snake Case)로 설정된 경우가 일반적.
대소문자 민감성
- 일부 데이터베이스(MariaDB, MySQL 등)는 설정에 따라 테이블 이름과 컬럼 이름의 대소문자를 구분합니다.
- Camel Case를 사용할 경우 대소문자 구분으로 인해 쿼리 실행 시 오류가 발생할 수 있습니다.
컨벤션 혼합 사용 문제
- 테이블/컬럼 이름에 Snake Case와 Camel Case를 혼용하면 가독성과 유지보수성이 떨어집니다.
- 일관된 규칙을 정해 사용하는 것이 중요합니다
JPA의 @Column 애너테이션으로 컬럼 이름을 명시하면 Snake Case와 Camel Case를 명확히 구분할 수 있습니다.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "created_at")
private LocalDateTime createdAt;
}
참고
'Spring' 카테고리의 다른 글
영속성 컨텍스트와 엔티티의 생명 주기 (1) | 2025.01.14 |
---|---|
JPA - Entity 관련 애너테이션 (0) | 2025.01.14 |
JPA의 @GeneratedValue 전략 (0) | 2025.01.14 |
JPA/Hibernate 관련 설정 (application.properties) (0) | 2025.01.13 |
JPA(Java Persistence API) 개요 (0) | 2025.01.13 |