> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# ClickHouse Managed Postgres와 Spring Boot 함께 사용하기

> Spring Data JPA, PostgreSQL JDBC 드라이버, HikariCP, Flyway 마이그레이션을 사용하여 검증된 TLS 연결을 통해 Spring Boot 애플리케이션을 ClickHouse Managed Postgres에 연결합니다

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>베타</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>베타 기능</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.guides-spring-boot-beta" />

[Spring Boot](https://spring.io/projects/spring-boot)는 PostgreSQL JDBC 드라이버(pgjdbc)와 HikariCP 연결 풀을 통해 Postgres에 연결하며, 애플리케이션 시작 시 [Flyway](https://documentation.red-gate.com/flyway) 마이그레이션을 실행합니다. 이 가이드에서는 Flyway 마이그레이션으로 `todos` 테이블을 생성하고, Spring Data JPA REST 컨트롤러로 생성, 조회, 수정, 삭제 요청을 처리합니다. 모든 연결에는 TLS가 사용되며, 인증서 검증이 완전하게 수행됩니다.

<h2 id="prerequisites">
  사전 요구 사항
</h2>

* JDK 17 이상(Spring Boot 4 요구 사항). 이 가이드는 Java 25, Spring Boot 4.1.1, pgjdbc 42.7.13, Hibernate 7.4.5, HikariCP 7.0.2, Flyway 12.4.0 환경에서 테스트되었습니다.
* ClickHouse Cloud 계정
* 데이터베이스 생성에 사용할 [`psql`](https://www.postgresql.org/download/). [SQL 콘솔](/ko/integrations/connectors/sql-clients/sql-console)에서 `CREATE DATABASE` SQL 문을 실행해도 됩니다.

<h2 id="create-service">
  ClickHouse Managed Postgres 서비스 생성
</h2>

ClickHouse Cloud 콘솔에서 **New service**를 클릭한 다음 **Postgres**를 선택하십시오. 인스턴스는 몇 분 안에 준비됩니다. 단계별 안내는 [빠른 시작 가이드](/ko/products/managed-postgres/quickstart)를 참조하십시오.

<h2 id="connection-details">
  연결 정보 확인하기
</h2>

서비스의 왼쪽 사이드바에서 **Connect**를 클릭하십시오. 모달에는 사용자 이름, 비밀번호, 서버, 포트가 표시되며, **Directly** / **via PgBouncer** 토글도 있습니다.

**Directly**가 선택된 상태에서 **Use SSL**을 켜고 **jdbc** 탭을 여십시오. 이 탭에 표시되는 JDBC URL은 두 가지만 수정하면 Spring Boot에서 사용할 수 있습니다. 수정할 항목은 데이터베이스 이름과 CA 인증서 파일 이름이며, [연결 구성하기](#configure-connection)에서 변경합니다.

```text theme={null}
jdbc:postgresql://your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem
```

JDBC URL에는 사용자 이름과 비밀번호가 포함되지 않습니다. Spring Boot는 이 값들을 별도의 속성에서 읽어옵니다.

이 가이드에서는 포트 `5432`를 통해 Postgres에 **직접** 연결합니다. Spring Boot 앱은 자체 HikariCP 풀(기본 10개 연결)을 유지하는 장기 실행 프로세스이므로 Postgres 앞에 별도의 풀러를 둘 필요가 없습니다. 앱 인스턴스 수와 풀 크기를 곱한 값이 서비스의 `max_connections`를 넘지 않도록 하십시오. 인스턴스를 많이 실행한다면 [PgBouncer 사용](#pgbouncer)을 참조하십시오.

모달에서 **Download CA certificate**를 클릭하십시오. **Settings → CA Certificate**에서도 다운로드할 수 있습니다. 이 인증서는 인스턴스마다 고유하므로, 드라이버는 이 인증서로 통신 대상이 해당 인스턴스의 서버가 맞는지 검증할 수 있습니다.

<h2 id="project-setup">
  프로젝트 설정
</h2>

[Spring Initializr](https://start.spring.io/)에서 Spring Web, Spring Data JPA, Flyway Migration, PostgreSQL Driver 의존성을 추가하여 Maven 프로젝트를 생성하십시오:

```bash theme={null}
curl https://start.spring.io/starter.tgz \
  -d type=maven-project \
  -d dependencies=web,data-jpa,flyway,postgresql \
  -d artifactId=todos -d name=todos -d baseDir=todos | tar -xzf -
cd todos
```

<Tip>
  **기존 앱에 추가하는 경우**

  `curl` 명령은 건너뛰십시오. `pom.xml`에 `spring-boot-starter-data-jpa`, `spring-boot-starter-flyway`, `org.flywaydb:flyway-database-postgresql` 의존성과 `runtime` 범위의 `org.postgresql:postgresql`을 추가하고, 앱에서 H2를 사용 중이라면 `com.h2database:h2`를 제거하십시오. 그런 다음 [연결 구성](#configure-connection) 단계를 진행하십시오.
</Tip>

<h2 id="configure-connection">
  연결 구성
</h2>

다운로드한 CA 인증서를 프로젝트 디렉터리로 옮긴 다음 파일 이름을 `ca-certificate.pem`으로 변경하십시오.

애플리케이션용 데이터베이스를 생성하십시오. `<PASSWORD>`와 호스트는 **Connect** 모달에 표시된 값으로 바꾸십시오.

```bash theme={null}
psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "CREATE DATABASE guide_spring;"
```

```text theme={null}
CREATE DATABASE
```

`src/main/resources/application.properties`의 내용을 다음으로 교체하십시오. 기존 앱이라면 `spring.datasource` 및 `spring.jpa` 줄을 추가하고, H2 URL 등 다른 `spring.datasource` 설정은 모두 제거하십시오. URL은 **jdbc** 탭에 표시된 값을 사용하되, 데이터베이스는 `guide_spring`으로, `sslrootcert`는 이름을 바꾼 파일로 변경합니다:

```properties title="src/main/resources/application.properties" theme={null}
spring.application.name=todos
server.port=3113

spring.datasource.url=jdbc:postgresql://your-instance.pg.clickhouse.cloud:5432/guide_spring?sslmode=verify-full&sslrootcert=ca-certificate.pem
spring.datasource.username=postgres
spring.datasource.password=${DATABASE_PASSWORD}

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.open-in-view=false
```

pgjdbc는 URL에서 `sslmode=verify-full`과 `sslrootcert`를 읽습니다. CA 파일에 있는 모든 인증서를 로드하고 인증서 체인과 호스트명을 모두 검사하므로 별도의 TLS 코드가 필요하지 않습니다. Spring Boot는 `DATABASE_PASSWORD` 환경 변수에서 비밀번호를 읽으므로 비밀번호를 파일에 저장하지 않아도 됩니다.

나머지 설정은 다음과 같습니다.

* `ddl-auto=validate`를 설정하면 Hibernate가 시작 시 엔터티가 Flyway에서 생성한 테이블과 일치하는지 검사합니다. Hibernate는 스키마를 변경하지 않습니다.
* `open-in-view=false`를 설정하면 HTTP 응답이 작성될 때까지 연결을 붙잡아 두지 않고, 트랜잭션이 끝나는 즉시 각 연결을 풀에 반환합니다.

<Note>
  `sslrootcert`에 상대 경로를 지정하면 JVM의 작업 디렉터리를 기준으로 해석됩니다. `./mvnw spring-boot:run`은 프로젝트 디렉터리에서 앱을 시작하므로 이 경우에는 `ca-certificate.pem`을 그대로 사용할 수 있습니다. 패키징된 JAR를 다른 위치에서 실행할 때는 절대 경로를 사용하세요. pgjdbc는 `~`를 확장하지 않습니다.

  **Use SSL**을 끈 상태에서 URL을 복사하면 `sslmode`가 포함되지 않으며, 이때 pgjdbc는 `prefer`를 사용합니다. 즉, 연결은 암호화하지만 서버는 검증하지 않습니다. CA가 잘못되었으면 `PKIX path building failed` 오류와 함께 연결에 실패합니다. 파일이 없으면 `Could not open SSL root certificate file` 오류가 발생합니다. IP 주소로 연결하는 경우처럼 호스트가 인증서와 일치하지 않으면 `The hostname ... could not be verified by hostnameverifier PgjdbcHostnameVerifier` 오류가 발생합니다.
</Note>

<h2 id="migrations">
  Flyway로 테이블 생성하기
</h2>

Flyway는 애플리케이션이 시작될 때 Hibernate가 스키마를 검사하기 전에 `src/main/resources/db/migration`에 있는 SQL 파일을 버전 순서대로 실행합니다. `src/main/resources/db/migration/V1__create_todos.sql` 파일을 생성하십시오.

```sql title="src/main/resources/db/migration/V1__create_todos.sql" theme={null}
CREATE TABLE todos (
    id         bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    title      text        NOT NULL,
    done       boolean     NOT NULL DEFAULT false,
    created_at timestamptz NOT NULL DEFAULT now()
);
```

Flyway는 적용된 각 파일을 `flyway_schema_history` 테이블에 기록하며, 이후 다시 시작할 때는 새 파일만 실행합니다. 스키마를 변경하려면 이미 실행된 파일을 수정하지 말고 `V2__add_due_date.sql`과 같은 새 파일을 추가하세요.

<Note>
  H2를 사용하던 앱에서는 보통 Hibernate가 테이블을 생성했습니다. 내장 데이터베이스에서는 `ddl-auto`의 기본값이 `create-drop`이기 때문입니다. Postgres에서는 기본값이 `none`이므로, 기존 테이블을 생성하는 마이그레이션을 추가하세요. 또한 별도 옵션 없이 `@GeneratedValue`만 지정한 `@Id`에는 엔터티 이름을 딴 시퀀스(예: `Employee`라면 `employee_seq`)가 필요하며, 이 시퀀스는 Hibernate의 기본 할당 크기인 `50`씩 증가해야 합니다. 그렇지 않으면 시작 시 `Schema validation: missing sequence [employee_seq]` 오류가 발생하고, 시퀀스가 `1`씩 증가하도록 설정되어 있으면 `The increment size of the [employee_seq] sequence is set to [50] in the entity mapping but the mapped database sequence increment size is [1]` 오류가 발생합니다.

  ```sql theme={null}
  CREATE SEQUENCE employee_seq INCREMENT BY 50;
  ```
</Note>

<h2 id="query">
  데이터베이스 쿼리하기
</h2>

`src/main/java/com/example/todos/Todo.java`에 엔터티를 생성하세요. Spring Boot는 `createdAt` 필드를 `created_at` 컬럼에 매핑합니다.

```java title="src/main/java/com/example/todos/Todo.java" theme={null}
package com.example.todos;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.Instant;

@Entity
@Table(name = "todos")
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private boolean done;

    private Instant createdAt = Instant.now();

    protected Todo() {
    }

    public Todo(String title) {
        this.title = title;
    }

    public Long getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    public Instant getCreatedAt() {
        return createdAt;
    }
}
```

`src/main/java/com/example/todos/TodoRepository.java`에 Spring Data 리포지토리를 생성하세요. 이 인터페이스의 구현은 Spring Data가 런타임에 자동으로 제공합니다.

```java title="src/main/java/com/example/todos/TodoRepository.java" theme={null}
package com.example.todos;

import org.springframework.data.jpa.repository.JpaRepository;

public interface TodoRepository extends JpaRepository<Todo, Long> {
}
```

`src/main/java/com/example/todos/TodoController.java`에 REST 컨트롤러를 생성하고, 라우트마다 리포지토리를 한 번씩 호출하도록 작성하십시오:

```java title="src/main/java/com/example/todos/TodoController.java" theme={null}
package com.example.todos;

import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

@RestController
@RequestMapping("/todos")
public class TodoController {

    record NewTodo(String title) {
    }

    private final TodoRepository todos;

    public TodoController(TodoRepository todos) {
        this.todos = todos;
    }

    // Read
    @GetMapping
    public List<Todo> list() {
        return todos.findAll(Sort.by("id"));
    }

    // Create
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Todo create(@RequestBody NewTodo body) {
        return todos.save(new Todo(body.title()));
    }

    // Update: toggle the done flag
    @PatchMapping("/{id}")
    public Todo toggle(@PathVariable Long id) {
        Todo todo = todos.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
        todo.setDone(!todo.isDone());
        return todos.save(todo);
    }

    // Delete
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {
        todos.deleteById(id);
    }
}
```

각 리포지토리 호출은 HikariCP 풀에서 가져온 연결을 사용하여 개별 트랜잭션으로 실행됩니다. 여러 호출을 하나의 트랜잭션으로 묶으려면 해당 호출들을 `@Transactional` 어노테이션이 지정된 메서드 안에 넣으세요.

<h2 id="verify">
  실행 및 확인
</h2>

비밀번호를 설정하고 앱을 시작하십시오:

```bash theme={null}
export DATABASE_PASSWORD='<PASSWORD>'
./mvnw spring-boot:run
```

처음 시작할 때 Flyway는 웹 서버가 시작되기 전에 마이그레이션을 적용합니다. 로그에는 다음과 같은 내용이 출력됩니다. 여기서는 타임스탬프와 스레드 이름을 생략하고 표시합니다:

```text theme={null}
o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "1 - create todos"
o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "public", now at version v1 (execution time 00:00.236s)
org.hibernate.orm.core                   : HHH000001: Hibernate ORM core version 7.4.5.Final
o.s.boot.tomcat.TomcatWebServer          : Tomcat started on port 3113 (http) with context path '/'
com.example.todos.TodosApplication       : Started TodosApplication in 5.619 seconds (process running for 5.744)
```

두 번째 터미널에서 할 일 2개를 생성하고, 첫 번째 항목은 완료로 표시한 다음 두 번째 항목은 삭제합니다.

```bash theme={null}
curl -w '\n' -X POST localhost:3113/todos -H 'Content-Type: application/json' -d '{"title": "Try Spring Boot"}'
curl -w '\n' -X POST localhost:3113/todos -H 'Content-Type: application/json' -d '{"title": "Write a Flyway migration"}'
curl -w '\n' -X PATCH localhost:3113/todos/1
curl -X DELETE localhost:3113/todos/2
```

`POST` 요청은 새로 생성된 행을 반환하고, `PATCH` 요청은 수정된 행을 반환합니다. `-w '\n'` 옵션은 각 응답 뒤에 줄 바꿈을 추가합니다.

```json theme={null}
{"title":"Try Spring Boot","createdAt":"2026-10-01T14:49:40.595598759Z","done":false,"id":1}
{"title":"Write a Flyway migration","createdAt":"2026-10-01T14:49:40.794631917Z","done":false,"id":2}
{"title":"Try Spring Boot","createdAt":"2026-10-01T14:49:40.595599Z","done":true,"id":1}
```

브라우저에서 [http://localhost:3113/todos](http://localhost:3113/todos)를 열면 남은 할 일 목록을 확인할 수 있습니다. 응답은 다음과 같습니다.

```json theme={null}
[{"title":"Try Spring Boot","createdAt":"2026-10-01T14:49:40.595599Z","done":true,"id":1}]
```

애플리케이션의 연결에 TLS가 사용되는지 확인하려면 애플리케이션이 실행 중인 상태에서 `pg_stat_ssl`을 쿼리하십시오.

```bash theme={null}
psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/guide_spring?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "SELECT ssl, version, count(*) AS connections FROM pg_stat_ssl JOIN pg_stat_activity USING (pid) WHERE datname = 'guide_spring' AND application_name = 'PostgreSQL JDBC Driver' GROUP BY ssl, version;"
```

```text theme={null}
 ssl | version | connections
-----+---------+-------------
 t   | TLSv1.3 |          10
(1 row)
```

10개의 연결은 HikariCP 풀에서 생성된 것입니다. <kbd>Ctrl</kbd>+<kbd>C</kbd>를 눌러 애플리케이션을 중지하세요.

콘솔에서 데이터를 확인하려면 서비스의 왼쪽 사이드바에서 **SQL 콘솔**을 열고 `guide_spring`과 `public`을 차례로 펼친 다음 `todos` 테이블을 클릭하세요. 그 옆에 있는 `flyway_schema_history` 테이블에는 마이그레이션 이력이 저장됩니다. `todos` 테이블에는 남아 있는 행이 다음과 같이 표시됩니다.

| id | title | done | created\_at |
| - | - | - | - |
| 1 | Try Spring Boot | true | 2026-10-01 14:49:40.595599+00 |

<h2 id="pgbouncer">
  PgBouncer 사용
</h2>

여러 앱 인스턴스의 연결 수를 합한 값이 Postgres 연결 한도에 가까워지면, 앱은 포트 `6432`에서 함께 제공되는 [PgBouncer](/ko/products/managed-postgres/connection#pgbouncer)를 통해 연결하고 Flyway는 계속 직접 연결을 사용하십시오. `application.properties`에서 `spring.datasource.url`의 포트를 `6432`로 변경하고, 그 아래에 다음 `spring.flyway` 행을 추가하십시오.

```properties title="src/main/resources/application.properties" theme={null}
spring.datasource.url=jdbc:postgresql://your-instance.pg.clickhouse.cloud:6432/guide_spring?sslmode=verify-full&sslrootcert=ca-certificate.pem
spring.flyway.url=jdbc:postgresql://your-instance.pg.clickhouse.cloud:5432/guide_spring?sslmode=verify-full&sslrootcert=ca-certificate.pem
spring.flyway.user=postgres
spring.flyway.password=${DATABASE_PASSWORD}
```

`spring.flyway.url`이 설정되어 있으면 Flyway는 자체 연결을 열며 `spring.datasource`의 사용자 이름과 비밀번호를 사용하지 않으므로, `spring.flyway.user`와 `spring.flyway.password`도 함께 설정하세요. 두 포트 모두 동일한 CA 인증서를 사용할 수 있습니다.

PgBouncer는 트랜잭션 풀링 모드(transaction pooling mode)로 실행되므로 트랜잭션마다 서로 다른 Postgres 연결에서 실행될 수 있습니다. Spring Boot를 사용할 때는 다음 사항에 유의하세요.

* **Prepared statement**는 기본 드라이버 설정으로 동작하므로 `prepareThreshold=0`을 지정할 필요가 없습니다. pgjdbc는 하나의 연결에서 같은 SQL 문이 다섯 번째로 실행될 때부터(`prepareThreshold`) 이름이 지정된 서버 측 prepared statement를 사용합니다. 이 SQL 문은 프로토콜 수준의 `Close` 메시지로 해제되며, 번들로 제공되는 PgBouncer가 이를 처리합니다.
* **pgjdbc 42.7.5 이상**이 필요합니다. 이전 버전은 `extra_float_digits` 시작 매개변수를 전송하므로, PgBouncer가 `FATAL: unsupported startup parameter: extra_float_digits` 오류와 함께 연결을 거부합니다. Spring Boot 4에는 최신 pgjdbc가 포함되어 있습니다. 이전 Spring Boot 버전에서는 `pom.xml`의 `<properties>` 섹션에 `<postgresql.version>42.7.13</postgresql.version>`을 설정하세요.
* **세션 설정은 유지되지 않습니다.** `SET` 문과 `Connection.setSchema`(HikariCP의 `spring.datasource.hikari.schema` 속성이 사용)는 해당 문을 실행한 Postgres 연결에만 적용되며, 다른 클라이언트에 영향을 줄 수 있습니다. `currentSchema` 및 `options` URL 매개변수는 `FATAL: unsupported startup parameter` 오류와 함께 실패합니다. 스키마를 명시한 테이블 이름을 사용하거나 트랜잭션 내에서 `SET LOCAL`을 사용하세요.
* **Flyway**는 트랜잭션 수준의 advisory 잠금을 사용하므로 기본 설정으로 PgBouncer를 통해 동작합니다. `CREATE INDEX CONCURRENTLY`를 실행하는 마이그레이션에는 `spring.flyway.postgresql.transactional-lock=false`가 필요하며, 이 설정을 사용하면 Flyway가 세션 수준 잠금으로 전환됩니다. PgBouncer를 거치면 이 잠금은 `Unable to release PostgreSQL advisory lock` 오류와 함께 실패하고 풀링된 연결에 그대로 남으므로, Flyway에는 직접 연결을 사용하세요.
* **풀 크기**: 각 HikariCP 연결은 PgBouncer에 대한 부담이 적은 클라이언트 연결입니다. PgBouncer는 애플리케이션 인스턴스가 여는 클라이언트 연결 수와 관계없이, 데이터베이스 및 사용자별로 여는 Postgres 연결 수를 제한합니다(`default_pool_size`). 이 한도를 초과한 트랜잭션은 HikariCP에서 실패하지 않고 PgBouncer에서 최대 `query_wait_timeout`(기본값 120초) 동안 대기합니다. HikariCP 풀을 늘려도 동시성은 이 한도까지만 높아지므로, 인스턴스당 기본값인 10으로 시작하는 것이 좋습니다. 자세한 내용은 [PgBouncer 및 Postgres 연결 한도](/ko/products/managed-postgres/faq#pgbouncer-vs-pg-connections)를 참조하세요.

`pg_stat_ssl`은 PgBouncer와 Postgres 간의 연결을 보고하므로, [실행 및 확인](#verify)의 TLS 쿼리에는 PgBouncer를 거치는 애플리케이션 연결이 표시되지 않습니다. 하지만 애플리케이션과 PgBouncer 간의 연결도 검증되므로, 잘못된 CA 인증서를 사용하면 마찬가지로 연결에 실패합니다.

<h2 id="next-steps">
  다음 단계
</h2>

* [연결](/ko/products/managed-postgres/connection): 연결 문자열(connection string), PgBouncer, TLS
* [설정](/ko/products/managed-postgres/settings): `max_connections` 등의 Postgres 및 PgBouncer 매개변수
* [읽기 레플리카(Read Replica)](/ko/products/managed-postgres/read-replicas): 읽기 전용 쿼리를 레플리카로 전송
* [보안](/ko/products/managed-postgres/security): IP 액세스 목록 및 프라이빗 네트워킹
