๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

๋ฉ€ํ‹ฐ DBํ™˜๊ฒฝ์—์„œ JPA ์‚ฌ์šฉ์‹œ ์ฃผ์˜์  (feat. connection leak)

by young-ji 2026. 2. 13.

spring data jpa

JPA์—์„œ Muti Datasource ์„ค์ •์— ๊ด€ํ•œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…์„ ๊ธฐ๋กํ•œ ํฌ์ŠคํŒ…์ž…๋‹ˆ๋‹ค. ์ตœ์ข… ์„ธํŒ… ๋ฐฉ์‹์€ ํ•˜๋‹จ์— ๊ธฐ์žฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ์ƒํ™ฉ

์ €ํฌ ์„œ๋น„์Šค๋Š” ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ์—์„œ ์—ฌ๋Ÿฌ๋Œ€์˜ DataBase๋ฅผ ์—ฐ๋™ํ•˜๋Š” ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ค‘์—์„œ ๋ช‡๊ฐœ์˜ DataBase๋งŒ ํ•„์š”์— ์˜ํ•ด JPA/QueryDsl์„ ์—ฐ๋™ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ตœ๊ทผ์— ์ƒˆ๋กœ์šด Datasource๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ QueryDsl์„ ์‚ฌ์šฉํ•˜๋˜ ์ค‘ ๋‹ค์Œ๊ณผ ๊ฐ™์€ connection leak warning์ด ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

java.lang.Exception: Apparent connection leak detected

๋ฌธ์ œ์˜ ์›์ธ์„ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด hikari๋กœ๊ทธ๋ฅผ ํ™•์ธํ•ด๋ณด๋‹ˆ, ์ฟผ๋ฆฌ๊ฐ€ ๋ชจ๋‘ ์‹คํ–‰๋œ ํ›„์—๋„ active connenction์ด ์œ ์ง€๋˜๊ณ  ์žˆ์—ˆ๊ณ (์ปค๋„ฅ์…˜์„ ๋ฐ˜๋‚ฉํ•˜์ง€ ์•Š์Œ) ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๊ณ  ๋‚˜๋‹ˆ connection์ด ์™„์ „ํžˆ close๋˜์–ด ์š”์ฒญ์„ ์•„์˜ˆ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

[HikariPool-3 housekeeper] [pool.HikariPool]- HikariPool-3 - Pool stats (total=10, active=1, idle=9, waiting=0)

..

could not prepare statement [Connection is closed] [select ...]

๋ฌธ์ œ๊ฐ€ ์žฌํ˜„๋œ ์š”์ฒญ์€ ์Šฌ๋กœ์šฐ ์ฟผ๋ฆฌ๊ฐ€ ์—†๋Š” ์š”์ฒญ์ด์˜€๊ณ  QueryDsl์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ์ ์„ ๋ณด์•„ ์„ค์ •์— ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋ผ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ž˜๋ชป๋œ ์ฝ”๋“œ

์•„๋ž˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ ์ฝ”๋“œ์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

@Bean("firstJpaQueryfactory")
public JPAQueryFactory firstJpaQueryfactory(
    @Qualifier("firstEntityManagerFactory") EntityManagerFatory entityManagerFatory
) {
    EntityManager entityManager = entityManagerFatory.createEntityManager();
    return new JPAQueryFactory(entityManager);
}

@Bean("secondJpaQueryfactory")
public JPAQueryFactory secondJpaQueryfactory(
    @Qualifier("secondEntityManagerFactory") EntityManagerFatory entityManagerFatory
) {
    EntityManager entityManager = entityManagerFatory.createEntityManager();
    return new JPAQueryFactory(entityManager);
}

ํ•ด๋‹น ์ฝ”๋“œ๋Š” ๋ฉ€ํ‹ฐ Datasource๋ฅผ ์‚ฌ์šฉํ•˜๋Š” JPAQueryFactory๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

๋‹จ์ผ DB ํ™˜๊ฒฝ์—์„œ๋Š” Spring์ด ์ž๋™์œผ๋กœ ๋นˆ์„ ์ฃผ์ž…ํ•ด์ฃผ๊ธฐ๋•Œ๋ฌธ์—(Querydsl 4.์ด์ƒ) ๋ณ„๋„ ์„ค์ • ์—†์ด๋„ JPAQueryFactory๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ DB ํ™˜๊ฒฝ์—์„œ๋Š” ๋™์ผํ•œ ํƒ€์ž…์˜ DataSource bean์ด ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค DataSource๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ• ์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉํ•˜๊ณ ์žํ•˜๋Š” DataSource ๋ณ„ EntityManagerFactory์™€ TransactionManager, JPAQueryFactory์™€ ๊ฐ™์€ JPA ๊ด€๋ จ bean๋“ค์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ตฌ์„ฑํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ์›์ธ

(๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์ฐพ์œผ์…จ๋‚˜์š”?)
์œ„ ์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ ์ด์œ ๋Š” JPAQueryFactory์— EntityManager๋ฅผ ์ง์ ‘ ์ฃผ์ž…ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

JPA๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์š”์ฒญ ๋‹น ํ•˜๋‚˜์˜ EntityManager๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ EntityManager๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ DB ์ปค๋„ฅ์…˜ ํ’€์„ ํ†ตํ•ด DB์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. EntityManager๋Š” thread-safeํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ ๊ฐ„ ๊ณต์œ ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋œ ํ›„์—๋Š” ์ปค๋„ฅ์…˜์„ ๋ฐ˜๋‚ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์Šคํ”„๋ง๊ณผ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ EntityManager๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ์œ„์ž„ํ•˜๋Š”๋ฐ, ์Šคํ”„๋ง์€ ์‹ฑ๊ธ€ํ†ค ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋นˆ์˜ ์†์„ฑ๊ฐ’์€ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณต์œ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์Šคํ”„๋ง์€ EntityManager์˜ thread-safe๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด EntityManager๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„์— ๋”ฐ๋ผ EntityManager๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ ํŠธ๋žœ์žญ์…˜๋งˆ๋‹ค ์ƒˆ๋กœ์šด EntityManager๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋˜๋ฉด ์ž๋™์œผ๋กœ EntityManager๊ฐ€ ๋‹ซํžˆ๊ณ  ์ปค๋„ฅ์…˜์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

 

์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด EntityManagerFatory๋ฅผ ์ฃผ์ž… ๋ฐ›์•„ EntityManager๋ฅผ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ JPAQueryFactory๊ฐ€ ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹Œ ์‹ค์ œ EntityManager ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์š”์ฒญ์ด ์ข…๋ฃŒ๋˜์–ด๋„ ์ปค๋„ฅ์…˜์ด ๋ฐ˜๋‚ฉ๋˜์ง€ ์•Š๊ณ , ๋ชจ๋“  ์š”์ฒญ์—์„œ ๋™์ผํ•œ ์ปค๋„ฅ์…˜์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

EntityManager๊ฐ€ thread-safeํ•˜์ง€ ์•Š์œผ๋ฉด race condition์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ flush๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ๋ฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ

EntityManager๋Š” thread-safeํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” EntityManager ๊ฐ์ฒด๋ฅผ bean์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ์•ˆ๋˜๊ณ  ์ง์ ‘ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ์—๋Š” @PersistenceContext๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

 

์ž˜๋ชป๋œ ์ฃผ์ž… ๋ฐฉ๋ฒ•

@Service
public class ProblematicService {
    private final EntityManagerFactory emf;
    private final EntityManager em;  // ์ง์ ‘ ์ƒ์„ฑํ•œ EntityManager

    public ProblematicService(EntityManagerFactory emf) {
        this.emf = emf;
        this.em = emf.createEntityManager();  // ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•ˆ ๋จ!
    }
}

์˜ฌ๋ฐ”๋ฅธ ์ฃผ์ž… ๋ฐฉ๋ฒ•

@Service
public class RecommendedService {
    // 1. ์ƒ์„ฑ์ž ์ฃผ์ž…
    private final EntityManager em;

    public RecommendedService(EntityManager em) {
        this.em = em;
    }
}
@Service
public class RecommendedService {
    // 2. @PersistenceContext ์‚ฌ์šฉ
    @PersistenceContext
    private EntityManager entityManager;
}

 

Spring boot 2.0 ๋ถ€ํ„ฐ๋Š” @Autowired๋กœ๋„ EntityManager์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์Šคํ”„๋ง๋ถ€ํŠธ๊ฐ€ ์ž๋™์œผ๋กœ @PersistenceContext๋กœ ๋Œ€์ฒดํ•ด ๋นˆ์„ ๋“ฑ๋กํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

์œ„ ๋ฌธ์ œ์˜ ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐœ์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@Configuration
public class QuerydslConfig {

    @PersistenceContext(unitName = "firstEntityManager")
    private EntityManager firstEntityManager;

    @PersistenceContext(unitName = "secondEntityManager")
    private EntityManager secondEntityManager;

    @PersistenceContext(unitName = "thirdEntityManager")
    private EntityManager thirdEntityManager;

    @Primary
    @Bean("firstjpaQueryFactory")
    public JPAQueryFactory firstJpaQueryFactory() {
        return new JPAQueryFactory(firstEntityManager);
    }

    @Bean("secondJpaQueryFactory")
    public JPAQueryFactory secondJpaQueryFactory() {
        return new JPAQueryFactory(secondEntityManager);
    }

    @Bean("thirdJpaQueryfactory")
    public JPAQueryFactory thirdJpaQueryfactory() {
        return new JPAQueryFactory(thirdEntityManager);
    }
}

Muti Datasource ์„ค์ • ๊ฐ€์ด๋“œ

์œ„ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ์ตœ์ข… ์„ค์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Datasource bean ์ถ”๊ฐ€

@Configuration
public class DataSourceConfig {

    private static final String FIRST_DATASOURCE = "firstDataSource";
    private static final String SECOND_DATASOURCE = "secondDataSource";
    private static final String THIRD_DATASOURCE = "thirdDataSource";

    @Primary // ๋ฉ”์ธ DB
    @Bean(FIRST_DATASOURCE)
    @ConfigurationProperties(prfix = "spring.datasource.first")
    public DataSource corownDataSource(){
        return DataSourceBuilder.create()
                    .type(HikariDataSource.class)
                    .build();
    }

    @Bean(SECOND_DATASOURCE)
    @ConfigurationProperties(prfix = "spring.datasource.second")
    public DataSource corbatDataSource(){
        return DataSourceBuilder.create()
                    .type(HikariDataSource.class)
                    .build();
    }

    @Bean(THIRD_DATASOURCE)
    @ConfigurationProperties(prfix = "spring.datasource.third")
    public DataSource custonDataSource(){
        return DataSourceBuilder.create()
                    .type(HikariDataSource.class)
                    .build();
    }
}

Transaction config ์ถ”๊ฐ€

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = "kr.co.sample.domain.first", // ํ•ด๋‹น DB๊ฐ€ ์žˆ๋Š” ํŒจํ‚ค์ง€(ํด๋”) ๊ฒฝ๋กœ
        entityManagerFactoryRef = "firstEntityManagerFactory", // EntityManagerFactory ์ด๋ฆ„
        transactionManagerRef = "firstTransactionManager" // TransactionManager ์ด๋ฆ„
)
public class FirstTransactionConfig {

    @Autowired
    @Qualifier("firstDataSource")
    private DataSource firstDataSource;

    @Bean(name = "firstEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(customDataSource)
                .packages("kr.co.sample.domain.first.entity") // ์ฒซ๋ฒˆ์งธ DB์™€ ๊ด€๋ จ๋œ ์—”ํ‹ฐํ‹ฐ๋“ค์ด ์žˆ๋Š” ํŒจํ‚ค์ง€(ํด๋”) ๊ฒฝ๋กœ
                .persistenceUnit("firstEntityManager")  // EntityManager unit ์ด๋ฆ„
                .build();
    }

    @Bean(name = "firstTransactionManager")
    public PlatformTransactionManager firstTransactionManager(
            final @Qualifier("firstEntityManagerFactory") LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean
    ) {
        return new JpaTransactionManager(localContainerEntityManagerFactoryBean.getObject());
    }
}

JpaQueryFactory bean ์ถ”๊ฐ€ (QueryDsl ์‚ฌ์šฉ์‹œ)

@Configuration
public class QuerydslConfig {

    @PersistenceContext(unitName = "firstEntityManager")
    private EntityManager corownEntityManager;

    @PersistenceContext(unitName = "secondEntityManager")
    private EntityManager secondEntityManager;

    @PersistenceContext(unitName = "thirdEntityManager")  // EntityManager unit ์ด๋ฆ„
    private EntityManager thirdEntityManager;

    @Primary
    @Bean("firstjpaQueryFactory")
    public JPAQueryFactory firstJpaQueryFactory() {
        return new JPAQueryFactory(firstEntityManager);
    }

    @Bean("secondJpaQueryFactory")
    public JPAQueryFactory secondJpaQueryFactory() {
        return new JPAQueryFactory(corbatEntityManager);
    }

    @Bean("thirdJpaQueryFactory")
    public JPAQueryFactory thirdJpaQueryFactory() {
        return new JPAQueryFactory(customEntityManager);
    }
}

์ปค์Šคํ…€ Tranactional ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€

@Transaction ์–ด๋…ธํ…Œ์ด์…˜ ๋˜ํ•œ default๋กœ Primary TransactionManager ๋นˆ์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—
์ถ”๊ฐ€ DataSource์— ๋Œ€ํ•œ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” value ์˜ต์…˜์„ ์ง€์ •ํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@Transactional(value = "secondTransactionManager")

 

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด custom transaction annotation์„ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional
public @interface SecondTransaction {

    String transactionManager() default "secondTransactionManager"; // TransactionManager ์ด๋ฆ„

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;
}

์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜์— @Transactional๋งŒ ๋ถ™์—ฌ์ฃผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ @Transactional๊ณผ ๊ฐ™์€ ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค.
readOnly์™€ ๊ฐ™์€ @Transactional์˜ ์†์„ฑ๋“ค๊ณผ ๋งค์นญ๋˜๋Š” ์†์„ฑ์„ ์ •์˜ํ•˜๋ฉด ์Šคํ”„๋ง์ด ์ด๋ฅผ ์ฝ๊ณ  @Transactional์˜ ์†์„ฑ์œผ๋กœ ์ธ์‹ํ•˜์—ฌ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 


 

์ด๋ฒˆ ํฌ์ŠคํŒ…์€ Spring์˜ EntityManager ํ”„๋ก์‹œ ๊ธฐ๋Šฅ๊ณผ Thread-safe์™€์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ„๊ณผํ•˜๊ณ  ๋ฐœ์ƒํ–ˆ๋˜ ์ด์Šˆ๋ฅผ ๋‹ค๋ค„๋ดค์Šต๋‹ˆ๋‹ค. Spring์—์„œ ์ œ๊ณตํ•ด์ฃผ๋˜ ๊ธฐ๋Šฅ์„ ์ปค์Šคํ…€ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” ํ•ญ์ƒ ์ฃผ์˜๊นŠ๊ฒŒ ์‚ดํŽด์•ผํ•œ๋‹ค๋Š” ๊ฑธ ๋‹ค์‹œ ํ•œ๋ฒˆ ๋А๊ผˆ์Šต๋‹ˆ๋‹ค. ๋๊นŒ์ง€ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿค—

๋Œ“๊ธ€