DB 설치 및 연결 확인까지 했으니, 이제 DB 에 Member 라는 테이블을 생성하고, Application 에도 Entity 를 생성하여 정보를 조회해보도록 하죠.
(ddl-auto : create 옵션을 줘도 되지만 이번에는 SQL 로 생성하도록 하겠습니다.)
CREATE TABLE public."member" (
member_id varchar(30) NOT NULL, -- 회원 ID
member_pw varchar(255) NOT NULL, -- 패스워드
member_nm varchar(50) NOT NULL, -- 사용자명
use_yn varchar(1) DEFAULT 'Y'::character varying NOT NULL, -- 사용여부
create_dt timestamp NOT NULL, -- 생성일시
update_dt timestamp NOT NULL, -- 수정일시
authority_cd varchar(20) NULL, -- 권한 코드
CONSTRAINT user_pk PRIMARY KEY (member_id)
);
COMMENT ON TABLE public."member" IS '사용자';
-- Column comments
COMMENT ON COLUMN public."member".member_id IS '회원 ID';
COMMENT ON COLUMN public."member".member_pw IS '패스워드';
COMMENT ON COLUMN public."member".member_nm IS '사용자명';
COMMENT ON COLUMN public."member".use_yn IS '사용여부';
COMMENT ON COLUMN public."member".create_dt IS '생성일시';
COMMENT ON COLUMN public."member".update_dt IS '수정일시';
COMMENT ON COLUMN public."member".authority_cd IS '권한 코드';
-- Permissions
ALTER TABLE public."member" OWNER TO aljjabaegi;
GRANT ALL ON TABLE public."member" TO aljjabaegi;
-- public."member" foreign keys
ALTER TABLE public."member" ADD CONSTRAINT member_authority_fk FOREIGN KEY (authority_cd) REFERENCES public.authority(authority_cd);
ALTER TABLE public."member" ADD CONSTRAINT member_team_fk FOREIGN KEY (team_id) REFERENCES public.team(team_id);
CREATE TABLE public.authority (
authority_cd varchar(20) NOT NULL, -- 권한 코드
authority_nm varchar(50) NOT NULL, -- 권한명
create_dt timestamp NOT NULL, -- 생성일시
update_dt timestamp NOT NULL, -- 수정일시
CONSTRAINT authority_pk PRIMARY KEY (authority_cd)
);
-- Column comments
COMMENT ON COLUMN public.authority.authority_cd IS '권한 코드';
COMMENT ON COLUMN public.authority.authority_nm IS '권한명';
COMMENT ON COLUMN public.authority.create_dt IS '생성일시';
COMMENT ON COLUMN public.authority.update_dt IS '수정일시';
-- Permissions
ALTER TABLE public.authority OWNER TO aljjabaegi;
GRANT ALL ON TABLE public.authority TO aljjabaegi;
회원 테이블과 권한 테이블을 생성했습니다. 추후 추가되는 기능에 따라 컬럼을 추가하도록 하겠습니다.
기존 API Application 에 JPA 관련 설정을 추가하겠습니다.
build.gradle 파일을 열어 dependencies 에 spring-boot-starter-data-jpa 를 추가하겠습니다. version 을 따로 명시하지 않으면 spring-boot-starter-parent
와 spring-boot-dependencies
에 의해 springboot 호환 버전으로 자동 설정 하게 됩니다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.1'
id 'io.spring.dependency-management' version '1.1.5'
}
group = 'com.geonlee'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
//postgresql
implementation group: 'org.postgresql', name: 'postgresql', version: '42.7.3'
runtimeOnly 'org.postgresql:postgresql'
//JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}
tasks.named('test') {
useJUnitPlatform()
}
spring:
application:
name: api
profiles:
active: dev
datasource:
hikari:
connection-timeout: 3000
validation-timeout: 3000
max-lifetime: 240000
jpa:
open-in-view: false #추가 설정
server:
port: 13713
servlet:
context-path: /my-api
encoding:
charset: utf-8
enabled: true
force: true
---
spring:
config:
activate:
on-profile: dev
datasource:
url: "jdbc:postgresql://localhost:15432/test_db"
driver-class-name: "org.postgresql.Driver"
username: "geonlee"
password: "geonlee"
hikari:
minimum-idle: 2
maximum-pool-size: 2
---
spring:
config:
activate:
on-profile: prod
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table
@Entity(name = "member")
public class Member {
@Id
@Column(name = "member_id")
private String memberId;
@Column(name = "member_pw")
private String password;
@Column(name = "member_nm")
private String memberName;
@Column(name = "use_yn")
private String useYn;
@Column(name = "authority_cd")
private String authorityCode;
@Column(name = "update_dt")
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime updateDate;
@Column(name = "create_dt", updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createDate;
}
같은 entity package 에 authority entity 도 생성합니다.
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table
@Entity(name = "authority")
public class Authority {
@Id
@Column(name = "authority_cd")
private String authorityCode;
@Column(name = "authority_nm")
private String authorityName;
@Column(name = "update_dt")
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime updateDate;
@Column(name = "create_dt", updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createDate;
}
DB table 과 JPA Entity 생성을 완료했습니다.
Entity Column 과 DB column 을 매핑하기 위해 @Column 을 사용하였고, 키인 member_id 에는 @Id 가 추가된 것을 보실 수 있습니다.
이제 다음 시간에는 MVC Model 로 Member 조회 요청에 의한 데이터 전송 API Operaion 을 생성해 보도록 하겠습니다.
application.yml 에 spring.jpa.open-in-view 설정을 하지 않으면 아래와 같은 경고를 볼 수 있습니다.
spring.jpa.open-in-view is enabled by default.
Therefore, database queries may be performed during view rendering.
Explicitly configure spring.jpa.open-in-view to disable this warning
open-in-view 의 default 설정은 true
입니다. 해당 옵션은 API 요청부터 응답까지 영속성 컨텍스트를 유지하겠다라는 설정입니다. 뭐 큰 문제가 있겠어 라고 생각할 수 있지만, Transaction 이 끝나도 DB 커넥션 풀을 반납하지 않기 때문에 Application 에 부하가 발생할 확율이 높고, DB Connection 수를 적게 설정할 경우 Dead lock
이 발생하여 Application 이 멈출 수도 있습니다. 이렇게 보면 왜 default 설정이 true 일까 라는 의문이 들지만, 대부분의 JPA 프로젝트에서 성능 최적화를 위해 lazy-loading 전략을 가지고 있고, 뷰에서 지연 로딩 된 특정 필드에 접근 시 세션이 닫혀 있으면 예외를 발생 시킬 수 있어, 이를 방지 하여 개발 편의성을 높이기 위해 default 설정이 true 인 것으로 생각됩니다.
여러 Database 의 날짜 타입에는 Date, Datetime, time, timestamp 등이 있습니다.
@Temporal 은 JPA 에서 날짜 타입의 필드를 표현할 때 사용합니다. @Temporal 을 사용하지 않을 경우 default 로 timestamp 로 설정됩니다.
TemporalType 에는 DATA, TIMESTAMP, TIME 이 있으니 날짜 타입의 필드에는 Temporal Annotaion 을 type에 맞추어 사용하도록 합니다.
@Temporal(TemporalType.DATE)
@Temporal(TemporalType.TIMESTAMP)
@Temporal(TemporalType.TIME)
Practice and train with fun programming programs. Explore and improve your skills with value-building soccer random programs. Follow you with lots of quality content and topics to share.
How will the
authority_cd column
in themember
table be populated, and what kind of data will be stored there? Retro Bowl