jpa:
open-in-view: true
hibernate:
ddl-auto: create
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
show-sql: true
properties:
hibernate.format_sql: true
!! 처음 한 번만 create로 해주고 나중에는 update로 바꿔줘야 함.
안 그럼 새로 런 할 때마다 기존에 있던 테이블 내용 날라가고(DROP) 새로 CREATE 된다.
sql실행 결과 콘솔창에 보여줌
원래 한 줄로 나오는데 format 맞춰서 예쁘게 보여줌
실행 후 로그 보면 ddl-auto: create
로 해뒀어서 drop table if exists User
라고 나온다.
Entity(table)를 만들 때 변수명 그대로 데이터베이스의 필드를 만들어준다.
default는 SpringPhysicalNamingStrategy
. camel case를 snake case로 바꿔서 데이터베이스 필드를 만들어준다.
package com.cos.blog.model;
public enum UserRole {
USER, ADMIN
}
package com.cos.blog.model;
import jakarta.persistence.*;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class User {
@Id // Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; // 시퀀스: AUTO_INCREMENT
@Column(nullable = false, length = 30)
private String username;
@Column(nullable = false, length = 100) // 비밀번호 암호화를 위해 넉넉하게 잡아두기
private String password;
@Column(nullable = false, length = 50)
private String email;
@Enumerated(EnumType.STRING) // EnumType.
@ColumnDefault("'USER'")
private UserRole role;
@CreationTimestamp // 시간이 자동으로 입력
private Timestamp createDate;
}
강의에선 UserRole을 그냥 string 타입으로 썼지만
원랜 enum을 쓰는 게 권장된다길래 enum 타입으로 써줬음
이 때 주의할점~ USER라는 문자를 넣어줘야 하는 것이니 작은 따옴표로 감싸주고 그 다음 큰따옴표로 감싸줘야 한다~
@ColumnDefault("USER")
(X)
@ColumnDefault("'USER'")
(O)
Timestamp
타입을 쓸 때도 java.security
의 Timestamp가 아니라 java.sql
의 Timestamp를 써줘야 한다!
잘 만들어졌다.
와우.. jpa 정말.. 좋은 거구나...
package com.cos.blog.model;
import jakarta.persistence.*;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import java.sql.Timestamp;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob // 대용량 데이터 large object
@Column(columnDefinition = "longtext")
private String content; // summernote 사용. <html>태그가 섞여서 디자인이 됨 -> 대용량
@ColumnDefault("0")
private int count; // 조회수
@ManyToOne // Many=Board, User=One 한 명의 유저는 여러 개의 게시글을 쓸 수 있다.
@JoinColumn(name="userId")
private User user; // 작성자.
// 원래 DB는 오브젝트를 저장할 수 없다. FK를 써야한다. 그런데 자바는 오브젝트를 저장할 수 있다.
// ORM을 사용하면 오브젝트 코드를 DB로 매핑시킬 수 있다.
@CreationTimestamp
private Timestamp createDate;
}
그래서 @Column(columnDefinition = "longtext")
을 써줬다.
설명 굿👍
https://jeong-pro.tistory.com/231
요약: 1:N보단 N:1을 사용, 1:1일 때 주 테이블에 외래 키를 가지도록, N:N은 사용금지
@Entity
가 클래스에 가장 가까이 붙어있는 게 좋다.
이 클래스가 ORM 클래스란 걸 보여주는 걸 제일 가깝게 위치시키는 게 좋기 때문에
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Reply {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 200)
private String content;
@ManyToOne // N:1 여러 개의 답변이 하나의 게시글에 존재할 수 있다. 답변이 N.
@JoinColumn(name = "boardId")
private Board board;
@ManyToOne // N:1 여러 개의 답변을 한 명의 유저가 쓸 수 있다. 답변이 N.
@JoinColumn(name = "userId")
private User user;
@CreationTimestamp
private Timestamp createDate;
}
@Data : getter, setter
@NoArgsConstructor : 기본 생성자
@AllArgsConstructor : 꽉 찬 생성자
@Builder : 빌더패턴
@Entity : ORM 클래스
@ManyToOne과 @JoinColumn이 한 쌍이라고 보면 될듯.
@JoinColumn의 name
속성으로 외래 키(Foreign Key) 컬럼의 이름을 지정한다.
생략이 가능하긴 한데 이 경우 엔티티이름_id 로 매핑이 된다.
referencedColumnName
속성으로 참조할 엔티티의 기본 키 컬럼의 이름을 지정할 수 있는데, 지정하지 않는다면 기본적으로 매핑되는 엔티티의 기본 키(ID) 컬럼이 적용된다.
외래키는 N이 되는 쪽에 있어야 함.
java.security 말고 java.sql Timestamp로
@CreationTimestamp 사용
= FK를 누가 가지고 있는가
양방향 매핑에서는 연관관계의 주인(FK를 가지고 있는 쪽)을 정해야 한다!
테이블로 보면 단방향 관계지만, 객체 입장에서는 양방향 관계로 만들어줘야 할 때가 있다.
https://yanoo.tistory.com/121
N:1 쪽에서 N이 FK를 가지고 있어야 한다.
@ManyToOne과 @JoinColumn을 한 쌍으로 써준다고 보면 된다.
보통
@ManyToOne
@JoinColumn(name = "")
식으로 써주는데
@JoinColumn의 name속성은 단지 FK의 이름을 생성해주는 역할이다.
그렇다면 연관관계는 어떻게 이루어지는 것인가? 하면
referencedColumnName 속성으로 FK가 조인할 대상의 컬럼명을 설정해줘야 한다.
그런데 이를 생략하면 해당 테이블의 PK가 자동으로 할당된다.
👍https://www.inflearn.com/questions/113969/comment/85022
또한 name 속성도 생략할 수 있는데, 이 경우 엔티티명_id로 이름이 자동생성된다.
이 때 1 쪽에선 FK가 필요하지 않다.
그래서 @OneToMany를 해주고 mappedBy 속성을 사용해줘야 한다.
자신은 FK가 아니며 DB에 컬럼을 만들지 말라고 알려주는 것!
mappedBy 다음엔 연결될 엔티티의 변수명
을 적어준다!
@OneToMany(mappedBy = "")
@ManyToOne은 기본 FetchType이 FetchType.EAGER 즉시로딩!
@OneToMany는 기본 FetchType이 FetchType.LAZY 지연로딩!
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity // ORM 클래스
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob // 대용량 데이터 large object
@Column(columnDefinition = "longtext")
private String content; // summernote 사용. <html>태그가 섞여서 디자인이 됨 -> 대용량
@ColumnDefault("0")
private int count; // 조회수
@ManyToOne // Many=Board, User=One 한 명의 유저는 여러 개의 게시글을 쓸 수 있다.
@JoinColumn(name="userId")
private User user; // 작성자.
// 원래 DB는 오브젝트를 저장할 수 없다. FK를 써야한다. 그런데 자바는 오브젝트를 저장할 수 있다.
// ORM을 사용하면 오브젝트 코드를 DB로 매핑시킬 수 있다.
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER) // mappedBy 연관관계의 주인이 아니다. (난 FK가 아니에요. DB에 컬럼을 만들지 마세요)
private List<Reply> reply;
@CreationTimestamp
private Timestamp createDate;
}