0206 ~ 0226


# 0206 ~ 0226

# 0214 - Thread dump์™€ Heap dump

๊ฐœ๋ฐฉ์šฉ์–ด๋กœ์จ dump๋Š” ์‹œ์Šคํ…œ์— ์ €์žฅ๋œ ์ •๋ณด๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ฝ‘์€ ๊ฒƒ. ๋˜๋Š” ๊ทธ์™€ ๊ฐ™์€์ผ๋กœ ์“ฐ์ธ๋‹ค. ์ผ์ข…์˜ snapshot ๊ฐœ๋…์ธ๋ฐ ์ฃผ๋กœ ๋ถ„์„ ์ตœ์ ํ™”์— ๋งŽ์ด ์“ฐ์ธ๋‹ค. DB dump, Thread dump ๋“ฑ์ด ์žˆ๋‹ค.

# Thread Dump

  • ํ”„๋กœ์„ธ์Šค์— ์†ํ•œ ๋ชจ๋“  thread๋“ค์˜ ์ƒํƒœ๋ฅผ ๊ธฐ๋กํ•œ๊ฒƒ
  • ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” thread๋“ค ์ค‘ ์ผ๋ถ€๋Š” JVM ๋‚ด๋ถ€ thread ์ด๊ณ  ์ผ๋ถ€๋Š” ์‹คํ–‰์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ thread์ด๋‹ค
  • Thread dump๋Š” ๋ฐœ์ƒ๋œ ๋ฌธ์ œ๋“ค์„ ์ง„๋‹จ, ๋ถ„์„ํ•˜๊ณ  jvm ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค€๋‹ค
  • ์˜ˆ๋ฅผ ๋“ค์–ด Thread dump๋Š” ์ž๋™์œผ๋กœ ๋ฐ๋“œ๋ฝ์„ ํ‘œ์‹œํ•œ๋‹ค

๋ฐ๋“œ๋ฝ์ด๋ž€? ์šด์˜์ฒด์ œ ํ˜น์€ ์†Œํ”„ํŠธ์›จ์–ด์˜ ์ž˜๋ชป๋œ ์ž์› ๊ด€๋ฆฌ๋กœ ์ธํ•˜์—ฌ ๋‘˜ ์ด์ƒ์˜ ํ”„๋กœ์„ธ์Šค(์‹ฌํ•˜๋ฉด ์šด์˜์ฒด์ œ ์ž์ฒด๋„ ํฌํ•จ)๊ฐ€ ํ•จ๊ป˜ ๋ฉˆ์ถ”์–ด ๋ฒ„๋ฆฌ๋Š” ํ˜„์ƒ์„ ๋งํ•œ๋‹ค
์šฐ๋ฆฌ๋‚˜๋ผ ๋ง๋กœ ๊ต์ฐฉ์ƒํƒœ๋ผ๊ณ  ํ•œ๋‹ค
๋ฐ๋“œ๋ฝ์€ ๋‘ ๊ฐœ ์ด์ƒ์˜ Thread์—์„œ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๋Œ€์˜ ์ž‘์—…์ด ๋๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค

# Heap Dump

  • ํŠน์ • ์‹œ์ ์— JVM heap ์˜์—ญ์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐœ์ฒด์˜ ์Šค๋ƒ…์ƒท
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋Š” JVM ๊ตฌ์กฐ์—์„œ heap ์˜์—ญ์„ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค
  • GC๊ฐ€ ํž™์—์„œ ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ๋ชปํ•˜๋Š”๊ฒฝ์šฐ Java VisualVM์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์–ด๋‚ผ ์ˆ˜ ์žˆ

# [ Heap Dump ๋– ๋ณด๊ธฐ ]

# ์‹ค์‹œ๊ฐ„ ๋ถ„์„ํ•˜๊ธฐ
jmap -heap <PID>

# ํŒŒ์ผ๋กœ ์ถœ๋ ฅํ•˜๊ธฐ
jmap -dump:format=b,file=<FILE_OUTPUT> <PID>
1
2
3
4
5

# 0222 - @Transient

@Transient๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ์™€ ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ๊ณผ ๋งคํ•‘ํ•˜๊ณ  ์žˆ๋Š” ๊ด€๊ณ„๋ฅผ ์ œ์™ธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

@Entity  
public class Member{  
    @Id  
    private Long id; // PK  
    private String userId; // ์‚ฌ์šฉ์ž ์•„์ด๋””  
    private String password; // ๋น„๋ฐ€๋ฒˆํ˜ธ  
    private String confirmPassword; // ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์ž…๋ ฅ  
}
1
2
3
4
5
6
7
8
@Entity  
public class Member{  
    @Id  
    private Long id;  
    private String userId;  
    private String password;  
  
    // [1] @Transient ์„ ์–ธ  
    javax.persistence.@Transient  
    private String confirmPassword; // ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์ž…๋ ฅ ๋งคํ•‘ ์ œ์™ธ  
}
1
2
3
4
5
6
7
8
9
10
11

# @Transient ์ดํ•ด

@Transient๋Š” JPA์˜ ํ‘œ์ค€์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋Š” javax.persistence ํŒจํ‚ค์ง€์— ํฌํ•จ๋˜์–ด์žˆ๋Š” ์ปฌ๋Ÿผ์„ ์ œ์™ธํ•˜๊ธฐ(์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ ์‹œํ‚ค๊ธฐ) ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ปฌ๋Ÿผ ๋งคํ•‘ ๋ ˆํผ๋Ÿฐ์Šค ์• ๋…ธํ…Œ์ด์…˜์ด๋‹ค.

package javax.persistence;  
@Target({ElementType.METHOD, ElementType.FIELD})  
@Retention(RetentionPolicy.RUNTIME)  
public @interface Transient {}
1
2
3
4

@Transient๋Š” ๋ฉ”์„œ๋“œ์™€ ํ•„๋“œ์— ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ณ  @Entity ํด๋ž˜์Šค๋ฟ๋งŒ์•„๋‹ˆ๋ผ @MappedSuperclass, @Embeddable ํด๋ž˜์Šค์˜ ํ•„๋“œ๋‚˜ getter ๋ฉ”์„œ๋“œ์— ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity class, mapped superclass, or embeddable class. -ย Oracle Doc - @Transient (opens new window)

# [ ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ ]

๋ฌด์—‡๋ณด๋‹ค ์˜์†(persistence)์ด๋ผ๋Š” ๊ฐœ๋…์€ JPA์˜ ๊ฐ€์žฅ ๊ทผ๊ฐ„์ด ๋˜๋Š” ๊ฐœ๋…์ด๋‹ค. ๋‹ค์‹œ ๋งํ•ด JPA์—์„  ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence context)๋ผ๋Š” ๋…ผ๋ฆฌ์ ์ธ ํŒจ๋Ÿฌ๋‹ค์ž„์˜ ๊ตฌํ˜„์ฒด๋ผ ํ•  ์ˆ˜ ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €(Entity Manager)๊ฐ€ ์กด์žฌํ•˜๊ณ , ์ด ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์—์„œ @Entity ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค. image ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ์˜์† ์ƒํƒœ(managed, persistent state)์ผ ๋•Œ, ๋น„๋กœ์†Œ ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์— ์˜ํ•ด ๊ด€๋ฆฌ๋œ๋‹ค. ์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์— ์˜ํ•ด [1] ๋ณ€ํ™”์— ๋Œ€ํ•œ ์ž๋™ ๊ฐ์ง€(Dierty Checking), [2] CRUD SQL ์ž๋™ ์ƒ์„ฑ ์ž‘์—… ๋ฐ ๊ทธ์™ธ ์ผ๋ จ์˜ ๋ชจ๋“  JPA์˜ ๋‚ด๋ถ€์ ์ธ ๋™์ž‘ ํ”„๋กœ์„ธ์Šค์—์„œ ํ™œ์šฉ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋œ๋‹ค๋ฉด, ๋”๋Š” ํ•ด๋‹น ํ•„๋“œ๋‚˜ ๋ฉ”์„œ๋“œ๋Š” ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์˜ ๊ด€๋ฆฌ ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋จ์„ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰ ํ•ด๋‹น ํ•„๋“œ์— ๋Œ€ํ•ด @Transient ์• ๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜๊ฒŒ ๋˜๋ฉด ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋˜์–ด ์•ž์„œ ์„ค๋ช…ํ•œ [1, 2] ์ž‘์—…๋“ค์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ† ๋Œ€๋กœ "ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ๊ณผ ๋งคํ•‘์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค."๋ผ๊ณ  ์ดํ•ดํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

# @Transient ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ์™€ ์‚ฌ์šฉ๋ฒ•

@Entity  
public class Product {  
    @Id  
    private Long id;  
    private String name;  
    private BigDecimal price;  
    private boolean isEvent;  
    // ^-- ์˜์† ์ œ์™ธ ๋Œ€์ƒ  
  
    public void runEventProcess(){  
        if(isEvent){  
            // ... ์ด๋ฒคํŠธ ๋กœ์ง ์ˆ˜ํ–‰  
        }  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

isEnvent ํ•„๋“œ์˜ ๊ฒฝ์šฐ Hokking ๋ชฉ์ ์œผ๋กœ ํŠน์ • ๋‚ ์งœ๋‚˜ ์‹œ๊ฐ„์ด ๋˜๋ฉด ํ™œ์„ฑํ™”(true)๋˜์–ด, ์ƒํ’ˆ ๊ฐ€๊ฒฉ์— ๋Œ€ํ•œ ํ• ์ธ์œจ ์ ์šฉ๊ณผ ๊ฐ™์€ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ด๋ฒคํŠธ ๋กœ์ง์„ ์ ์šฉ ์‹œํ‚ค๊ธฐ ์œ„ํ•จ์ด๋‹ค.

์ด์ฒ˜๋Ÿผ ํŠน์ • ํ•„๋“œ์— ๋Œ€ํ•ด ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๊ณ , ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.

Hibernate:  
        create table product (  
        id bigint not null,  
        is_event boolean not null, <-- ์˜์† ์ œ์™ธ ๋Œ€์ƒ  
        name varchar(255),  
        price decimal(19,2),  
        primary key (id)  
        )
1
2
3
4
5
6
7
8

# [ @Transient ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹ ]

@Transient ์• ๋…ธํ…Œ์ด์…˜์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์„ ํ†ตํ•ด ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

  • ElementType.FIELD
@Entity  
public class Product{  
    @Id  
    private Long id;  
    private String name;  
    private BigDecimal price;  
    @Transient  
    private boolean isEvent;  
    // ^-- ํ•ด๋‹น ํ•„๋“œ ์˜์† ์ œ์™ธ ๋Œ€์ƒ  
}
1
2
3
4
5
6
7
8
9
10
  • ElementType.METHOD
@Entity  
public class Product{  
    private Long id;  
    private String isEvent;  
  
    @Id @GeneratedValue  
    public Long getId(){ return this.id; }  
    public void setId(Long id){ this.id = id; }  
    // ^-- @GeneratedValue๋Š” JPA์˜ ๋‚ด๋ถ€์ ์ธ ํ”„๋กœ์„ธ์Šค์— ์˜ํ•ด  
    // setter ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์…‹ํŒ…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ์„ฑํ•จ  
    @Transient // <-- ํ•ด๋‹น ๋ฉ”์„œ๋“œ ์˜์† ์ œ์™ธ ๋Œ€์ƒ  
    public String getIsEventProduct(){ return this.isEvent; }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13

๋‹ค์Œ ์ฝ”๋“œ๋Š” ํ•„๋“œ ๋ฐฉ์‹๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ์ฃผ์˜ํ•  ์ ์€ setter ๋ฉ”์„œ๋“œ๊ฐ€ ์•„๋‹Œ, getter ๋ฉ”์„œ๋“œ์— ์• ๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•ด์ค˜์•ผ ํ•œ๋‹ค.

# ๋ฉ”์„œ๋“œ/ํ•„๋“œ ๋ฐฉ์‹์„ ์ง€์›ํ•˜๋Š” JPA ์• ๋…ธํ…Œ์ด์…˜์˜ ์ฃผ์˜์‚ฌํ•ญ

# [ ๊ฐœ๋ฐœ ์˜๋„์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š” JPA ]

@Entity  
public class Member{  
    @Id  
    private Long id;  
    private String userId;  
    private String password;  
    private String confirmPassword;  
  
    @Transient // <-- ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๋ถ€๋ถ„  
    public String getComfirmPassword(){ return this.confirmPassword; }  
}
1
2
3
4
5
6
7
8
9
10
11
  • confirmPassword ํ•„๋“œ๋ฅผ ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•œ๋‹ค.
  • getComfirmPassword() ๋ฉ”์„œ๋“œ์— @Trasient ์• ๋…ธํ…Œ์ด์…˜ ์„ ์–ธ
  • ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒฐ๊ณผ -> ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ์ƒ์„ฑ ๋ฐ CRUD SQL๋ฌธ ๋Œ€์ƒ ์ปฌ๋Ÿผ ์ œ์™ธ
Hibernate:  
        create table member (  
        id bigint not null,  
        user_id varchar(255),  
        password varchar(255),  
        confirm_password varchar(255), <-- ํ•˜์ง€๋งŒ ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋˜์ง€ ์•Š์Œ  
        primary key (id)  
        )
1
2
3
4
5
6
7
8

ํ•˜์ง€๋งŒ ์‹ค์ œ ์ฝ”๋“œ๋Š” ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘๋œ๋‹ค.

# [ ๋ฌธ์ œ์˜ ์›์ธ ํŒŒ์•… - ์—”ํ‹ฐํ‹ฐ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์ดํ•ด ]

JPA ์ŠคํŽ™์— ๋”ฐ๋ฅด์ž๋ฉด, JPA๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์„ ํ†ตํ•ด ์˜์† ์ƒํƒœ(managed, persistent state)์ธ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ํ”„๋กœํผํ‹ฐ ๋ฐฉ์‹(getter/setter Method, JavaBeans Property ์Šคํƒ€์ผ)
  2. ํ•„๋“œ ๋ฐฉ์‹(Instance Fileds)

JPA 1.0(JSR 220) (opens new window)
JPA 2.0(JSR 317) (opens new window)
JPA 2.1(JSR 338) (opens new window)

// [1] ํ•„๋“œ ๋ฐฉ์‹  
@Entity  
public class Member{  
    @Id  
    private Long id;  
    private String name;  
    ...  
}  
  
// [2] ๋ฉ”์„œ๋“œ ๋ฐฉ์‹  
@Entity  
public class Member{  
    private Long id;  
    private String name;  
  
    @Id
    public Long getId(){return this.id;}  
    public void setId(Long id){this.id = id;}  
  
    public String getName(){return this.name;}  
    public void setName(String name){this.name = name;}  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

JPA์˜ ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹ ์ค‘ ์„ ํƒํ•˜์—ฌ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก, ํ•„๋“œ ๋ ˆ๋ฒจ์— ์„ ์–ธ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  JPA์˜ ์• ๋…ธํ…Œ์ด์…˜๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Property ๋ฐฉ์‹์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”์„œ๋“œ ๋ ˆ๋ฒจ์„ ์ง€์›ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํ•ต์‹ฌ์€ ์„ค๊ณ„ ๋ฐฉ์‹์— ๋”ฐ๋ผ JPA๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๊ฒŒ ๊ฒฐ์ •๋œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์˜ 1์ฐจ ์บ์‹œ๋Š” Map<@Id, @Entity> ํ˜•ํƒœ๋กœ ์„ค๊ณ„๋˜์–ด key์— ํ•ด๋‹นํ•˜๋Š” @Id์™€ value์— ํ•ด๋‹นํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜์—ฌ ๊ด€๋ฆฌํ•œ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ JPA์˜ ์—”ํ‹ฐํ‹ฐ์˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ @Id ์• ๋…ธํ…Œ์ด์…˜์˜ ์œ„์น˜์— ์˜ํ•ด ๊ฒฐ์ •๋˜๋ฉฐ, ์—”ํ‹ฐํ‹ฐ์˜ ๋ชจ๋“  ํ•„๋“œ ๋˜๋Š” ์ƒ์†๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๊ณ„์ธต์— ๋Œ€ํ•ด์„œ๋„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์—”ํ‹ฐํ‹ฐ์˜ ๊ณ„์ธต์— ๋Œ€ํ•ด์„œ๋„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.  
  
@Entity  
public class Member{  
    @Id // ํ•„๋“œ ๋ฐฉ์‹  
    private Long id;  
    private String userId;  
    private String password;  
    private String confirmPassword;  
  
    @Transient // JPA์—์„œ ์ธ์‹ ๋ถˆ๊ฐ€ โ†’ ๋™์ž‘ ์•ˆํ•จ  
    public String getComfirmPassword(){ return this.confirmPassword; }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13

๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋ฌธ์ œ๊ฐ€ ๋œ ์—”ํ‹ฐํ‹ฐ ๊ตฌ์กฐ์—์„  @Id ์• ๋…ธํ…Œ์ด์…˜์˜ ์œ„์น˜๊ฐ€ ํ•„๋“œ์— ์žˆ์œผ๋ฏ€๋กœ JPA๋Š” ํ•„๋“œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋”ฐ๋ฅด๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ confirmPassword ํ•„๋“œ๋Š” ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋˜์ง€ ์•Š๋Š”๋‹ค.

# [ ์ •๋ฆฌ ]

  1. @Transient๋Š” ์˜์† ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•œ๋‹ค.
  2. JPA ์ปฌ๋Ÿผ ๋งคํ•‘ ๋ ˆํผ๋Ÿฐ์Šค ์• ๋…ธํ…Œ์ด์…˜์€ Filed, Property ๋ฐฉ์‹์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ์— ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ์ปฌ๋Ÿผ ๋งคํ•‘ ๋ ˆํผ๋Ÿฐ์Šค ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ๋•Œ JPA์˜ ์—”ํ‹ฐํ‹ฐ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž.
    • @Id ์• ๋…ธํ…Œ์ด์…˜์˜ ์œ„์น˜๋ฅผ ๋ณด์ž.(@Access ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์žฌ์ •์˜ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ)
  4. QueryDSL ๋˜ํ•œ JPA์˜ ์—”ํ‹ฐํ‹ฐ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ธฐ์ค€์œผ๋กœ QDomain ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
    • ๋˜ํ•œ, @Transient ์• ๋…ธํ…Œ์ด์…˜์ด ์„ ์–ธ๋œ ํ•„๋“œ๋‚˜ ๋ฉ”์„œ๋“œ๋Š” QDomain ํด๋ž˜์Šค์˜ย ์ฟผ๋ฆฌ ํƒ€์ž… ์ƒ์„ฑ๊ณผ์ •์—์„œ ์ œ์™ธ๋œ๋‹ค.

# 0224 - Instant vs LocalDateTime

# Instant

  • Instant ํด๋ž˜์Šค๋Š” ๋‹จ์–ด์˜ ์˜๋ฏธ์™€ ๊ฐ™์ด ์ˆœ๊ฐ€, ์ฆ‰์‹œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • ์ปดํ“จํŒ…์„ ํ•˜๊ธฐ ์œ„ํ•ด Timestamp๋กœ ๊ธฐ์ˆ ์ ์ธ ํ‘œํ˜„์„ ํ•œ ๊ฒƒ.
    • ์ฆ‰, ์ธ๊ฐ„๋ณด๋‹ค๋Š” ๊ธฐ๊ณ„์— ์นœํ™”์ ์ด๋‹ค.
  • long ํ˜•ํƒœ๋กœ Unix Timestamp๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์‚ฐ์ด ๋น ๋ฅด๋‹ค.
  • Unix Timestamp ๋Š” Year 2038 problem ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด ์ด๋ฅผ ๋ณด์™„ํ•œ ๊ฒƒ์ด Instant ํด๋ž˜์Šค์ด๋‹ค.
  • ์ง€์› ๋ฒ”์œ„
    • MIN_SECONDย =ย -10000000-01-01T00:00Z
    • MAX_SECONDย =ย 1000000000-12-31T23:59:59.99999999Z
private static final long MIN_SECOND = -31557014167219200L; 
private static final long MAX_SECOND = 31556889864403199L;
1
2
  • ๊ฐ์ฒด ์ƒ์„ฑ
Instant now = Instant.now();
println(now); 
// 2022-08-08T16:09:17.105081Z -- 2022๋…„ 08์›” 09์ผ 01์‹œ 09๋ถ„ 17์ดˆ
1
2
3
  • ๋‚˜๋…ธ์ดˆ๊นŒ์ง€ ํ‘œํ˜„ ๊ฐ€๋Šฅ(๋’ค์— Z๋ฅผ ํ‘œํ˜„ํ•จ)
  • Timestamp๋Š” ๋ณธ๋ž˜ longํƒ€์ž…์ด๋‹ค. toString()์„ ์žฌ์ •์˜ ํ•จ.
public static Instant now(){  
        return Clock.currentInstant();  
        }  
  
public abstract class Clock {  
    private static final long OFFSET_SEED = System.currentTimeMillis() / 1000 - 1024;  
    private static long offset = OFFSET_SEED;  
  
    // ์‹œ์Šคํ…œ์˜ ํ˜„์žฌ ์‹œ๊ฐ„์„ ๊ฐ€์ ธ์˜จ๋‹ค ๋‚˜๋…ธ์ดˆ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ฐ€๋ฆฌ์ดˆ๋กœ ํ‘œํ˜„ํ•ด์ค€๋‹ค.  
    static Instant currentInstant() {  
        long localOffset = offset;  
        long adjustment = VM.getNanoTimeAdjustment(localOffset);  
        // ๋ฐ€๋ฆฌ์ดˆ๋ฅผ ๋‚˜๋…ธ์ดˆ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๊ฐ€์ ธ์˜จ๋‹ค  
            ...  
        return Instant.ofEpochSecond(localOffset, adjustment);  
    }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# LocalDateTime

  • LocalDateTime์€ ๋‚ ์งœ + ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. Timezone์ด ์—†๋‹ค.
  • LocalDateTime์€ ์ธ๊ฐ„์—๊ฒŒ ์นœํ™”์ ์ธ ํƒ€์ž…
  • LocalDateTime์€ ํ˜„์žฌ ๋กœ์ปฌ ์‹œ๊ฐ„์— ๋งž์ถฐ์„œ ์‹œ๊ฐ„์„ ํ‘œํ˜„
LocalDateTime now = LocalDateTime.now(); 
println(now); 
// 2022-08-09T01:09:17.113332 2022๋…„ 08์›” 09์ผ 01์‹œ 09๋ถ„ 17์ดˆ
1
2
3
  • ์ธ์Šคํ„ด์Šค์˜ Tiemzone ๊ธฐ๋ฐ˜์œผ๋กœ Offset์„ ์ƒ์„ฑํ•œ ํ›„ ํ˜„์žฌ ์‹œ์  ๊ธฐ์ค€์œผ๋กœ LocalDate, LocalTime ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ LocalDateTime์„ ์ƒ์„ฑํ•œ๋‹ค.
public final class LocalDateTime {  
    public static LocalDateTime now() {  
        return now(Clock.systemDefaultZone());  
    }  
}  
  
    public static Clock systemDefaultZone() {  
        // ์‹œ์Šคํ…œ์˜ ZoneId๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค   
return new SystemClock(ZoneId.systemDefault());  
    }  
  
    public static LocalDateTime now(Clock clock) {  
        Objects.requireNonNull(clock, "clock");  
        final Instant now = clock.instant();  
        // ZoneId๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Offset ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.   
ZoneOffset offset = clock.getZone().getRules().getOffset(now);  
        return ofEpochSecond(now.getEpochSecond(), now.getNano(), offset);  
    }  
  
    public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {  
        Objects.requireNonNull(offset, "offset");  
        NANO_OF_SECOND.checkValidValue(nanoOfSecond);  
        long localSecond = epochSecond + offset.getTotalSeconds();  
        long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);  
        int secsOfDay = Math.floorMod(localSecond, SECONDS_PER_DAY);  
        LocalDate date = LocalDate.ofEpochDay(localEpochDay);  
        LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + nanoOfSecond);  
        return new LocalDateTime(date, time);  
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# [ LocalDateTime์„ ์‚ฌ์šฉ ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ์  ]

  • ๊ธ€๋กœ๋ฒŒ ํ™˜๊ฒฝ์˜ ๊ฒฝ์šฐ UTC๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•ด ์ฃผ์ง€ ์•Š๋Š” ์ด์ƒ ๊ฐ๊ฐ Timezone์— ๋งž์ถฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

# [ ์–ด๋–ค ์ƒํ™ฉ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ• ๊นŒ ]

  • Timestamp๋ฅผ UTC ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๋Š” ๊ณณ ์ฆ‰ DB, ๋ฐฑ์—”๋“œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ๋ฐ์ดํ„ฐ ๊ตํ™˜, ์ง๋ ฌํ™” ์‹œ๋‚˜๋ฆฌ์˜ค์— ์ ํ•ฉํ•˜๋‹ค.(์—ฐ์‚ฐํ•˜๊ธฐ ์‰ฌ์›€)
  • ๊ธ€๋กœ๋ฒŒ ๋Ÿฐ์นญํ•œ ์„œ๋น„์Šค ๋น„์ฆˆ๋‹ˆ์Šค ์•ฑ ๊ฐœ๋ฐœ ์‹œ Instant ๋‚˜ ZonedDateTime ํด๋ž˜์Šค๋ฅผ ๋งŽ์ด ์‚ฌ์šฉ
Last update: March 1, 2023 23:42
Contributors: jaesungahn91