Prerequisite : Hibernate 0 - JBDC, JPA, Hibernate란?
-- PostgreSQL `comment` table
CREATE TABLE comment
(
id serial NOT NULL, -- AUTO INCREMENT PRIMARY KEY `id`
account_id text NOT NULL, -- 사용자 아이디
post_id integer NOT NULL, -- 원본 게시글 아이디
content text NOT NULL, -- 댓글 내용
like_cnt integer NOT NULL, -- 좋아요 카운트
created_at timestamp without time zone NOT NULL, -- 생성된 시간
depth smallint NOT NULL, -- 댓글, 대댓글 여부
bundle_id integer NOT NULL, -- 댓글 타래 아이디, 원본 댓글 id를 가르킨다.
PRIMARY KEY (id)
)
@Entity
@Table(name = "comment")
@Getter
@Setter
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "account_id")
private String accountId;
@Column(name = "post_id")
private Integer postId;
@Column(name = "content")
private String content;
@Column(name = "like_cnt")
private Integer likeCnt = 0;
@Column(name = "created_at")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS") // ISO-8601 formatting
private ZonedDateTime createdAt = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
@Column(name = "depth")
private Integer depth = 0;
@Column(name = "bundle_id")
private Integer bundleId;
}
위의 코드에서는 Entity, Table, Id, GeneratedValue, Column
annotation 들을 사용하여 PostgreSQL 에 있는 comment
테이블과 매핑을 정의하고 있다.
각 annotation들의 역할을 간단히 설명하자면 다음과 같다.
Entity : DB에 저장될 수 있는 자바 POJO로, DB에 저장되어 있는 테이블을 나타낸다. Entity instance는 테이블의 한 row를 나타낸다.
Table : Table annotation으로 정확히 어떤 테이블에 매핑 되는지 특정한다.
Id : Primary key를 정의한다. 모든 JPA entity는 반드시 primary key를 가지고 있어야 한다.
GeneratedValue : 이 annotation을 통해, identifier가 어떻게 생성되는지를 정의할 수 있다. 생성 방법에는 4가지 방법이 있다.
Column : Table이 Table을 지정하는 것 처럼, Column은 Column을 지정한다. 다음과 같은 elements들을 사용할 수 있다
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="STUDENT_NAME", length=50, nullable=false, unique=false)
private String name;
}
위에서 살펴본 annotation들은 JPA에 interface의 형태로 정의되어 있다.
어떤 식으로 정의되어 있는지 구경만 해보자 인터페이스 이기 때문에 껍데기 밖에 없다.
// Entity
/**
* Specifies that the class is an entity. This annotation is applied to the
* entity class.
*
* @since 1.0
*/
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface Entity {
/**
* (Optional) The entity name. Defaults to the unqualified
* name of the entity class. This name is used to refer to the
* entity in queries. The name must not be a reserved literal
* in the Jakarta Persistence query language.
*/
String name() default "";
}
// Table
/**
* Specifies the primary table for the annotated entity. Additional
* tables may be specified using {@link SecondaryTable} or {@link
* SecondaryTables} annotation.
*
* <p> If no <code>Table</code> annotation is specified for an entity
* class, the default values apply.
*
* <pre>
* Example:
*
* @Entity
* @Table(name="CUST", schema="RECORDS")
* public class Customer { ... }
* </pre>
*
* @since 1.0
*/
@Target(TYPE)
@Retention(RUNTIME)
public @interface Table {
/**
* (Optional) The name of the table.
* <p> Defaults to the entity name.
*/
String name() default "";
/** (Optional) The catalog of the table.
* <p> Defaults to the default catalog.
*/
String catalog() default "";
/** (Optional) The schema of the table.
* <p> Defaults to the default schema for user.
*/
String schema() default "";
/**
* (Optional) Unique constraints that are to be placed on
* the table. These are only used if table generation is in
* effect. These constraints apply in addition to any constraints
* specified by the <code>Column</code> and <code>JoinColumn</code>
* annotations and constraints entailed by primary key mappings.
* <p> Defaults to no additional constraints.
*/
UniqueConstraint[] uniqueConstraints() default {};
/**
* (Optional) Indexes for the table. These are only used if
* table generation is in effect. Note that it is not necessary
* to specify an index for a primary key, as the primary key
* index will be created automatically.
*
* @since 2.1
*/
Index[] indexes() default {};
}
// Id
/**
* Specifies the primary key of an entity.
* The field or property to which the <code>Id</code> annotation is applied
* should be one of the following types: any Java primitive type;
* any primitive wrapper type;
* <code>String</code>;
* <code>java.util.Date</code>;
* <code>java.sql.Date</code>;
* <code>java.math.BigDecimal</code>;
* <code>java.math.BigInteger</code>.
*
* <p>The mapped column for the primary key of the entity is assumed
* to be the primary key of the primary table. If no <code>Column</code> annotation
* is specified, the primary key column name is assumed to be the name
* of the primary key property or field.
*
* <pre>
* Example:
*
* @Id
* public Long getId() { return id; }
* </pre>
*
* @see Column
* @see GeneratedValue
*
* @since 1.0
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Id {}
// GeneratedValue
/**
* Provides for the specification of generation strategies for the
* values of primary keys.
*
* <p> The <code>GeneratedValue</code> annotation
* may be applied to a primary key property or field of an entity or
* mapped superclass in conjunction with the {@link Id} annotation.
* The use of the <code>GeneratedValue</code> annotation is only
* required to be supported for simple primary keys. Use of the
* <code>GeneratedValue</code> annotation is not supported for derived
* primary keys.
*
* <pre>
*
* Example 1:
*
* @Id
* @GeneratedValue(strategy=SEQUENCE, generator="CUST_SEQ")
* @Column(name="CUST_ID")
* public Long getId() { return id; }
*
* Example 2:
*
* @Id
* @GeneratedValue(strategy=TABLE, generator="CUST_GEN")
* @Column(name="CUST_ID")
* Long id;
* </pre>
*
* @see Id
* @see TableGenerator
* @see SequenceGenerator
*
* @since 1.0
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface GeneratedValue {
/**
* (Optional) The primary key generation strategy
* that the persistence provider must use to
* generate the annotated entity primary key.
*/
GenerationType strategy() default AUTO;
/**
* (Optional) The name of the primary key generator
* to use as specified in the {@link SequenceGenerator}
* or {@link TableGenerator} annotation.
* <p> Defaults to the id generator supplied by persistence provider.
*/
String generator() default "";
}
// Column
/**
* Specifies the mapped column for a persistent property or field.
* If no <code>Column</code> annotation is specified, the default values apply.
*
* <blockquote><pre>
* Example 1:
*
* @Column(name="DESC", nullable=false, length=512)
* public String getDescription() { return description; }
*
* Example 2:
*
* @Column(name="DESC",
* columnDefinition="CLOB NOT NULL",
* table="EMP_DETAIL")
* @Lob
* public String getDescription() { return description; }
*
* Example 3:
*
* @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
* public BigDecimal getCost() { return cost; }
*
* </pre></blockquote>
*
*
* @since 1.0
*/
@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;
}