> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ORM으로 MySQL 사용하기: Django, Rails, Prisma

> Django, Rails, Prisma를 MySQL에 맞게 올바르게 설정하기: 문자 집합과 strict 모드 설정, N+1 문제, 그리고 원시 SQL로 내려가야 할 때입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

ORM은 대부분의 애플리케이션이 실제로 MySQL과 대화하는 방식이고, 대부분의 ORM 문제는 몇 줄의 설정과 한 가지 쿼리 패턴으로 거슬러 올라갑니다. 이 가이드는 Django, Rails, Prisma를 위한 MySQL 쪽 설정과, ORM이 생성한 SQL이 제품의 느린 부분이 되지 않게 하는 습관을 다룹니다. VillageSQL은 MySQL의 드롭인 대체품이므로 여기의 모든 설정은 수정 없이 그대로 동작합니다: ORM은 차이를 알아차리지 못합니다.

## 어디서나 중요한 설정

프레임워크가 무엇이든 세 가지는 반드시 참이어야 합니다:

* **연결이 `utf8mb4`를 사용합니다.** 그렇지 않으면 이모지가 전송 중에 깨집니다. [utf8mb4와 이모지](https://villagesql.com/docs/ko/guides/utf8mb4.md)를 참고하세요.
* **Strict SQL 모드가 켜져 있습니다**(MySQL 8.x의 기본값). 그래서 잘못된 데이터는 조용히 잘리는 대신 오류를 냅니다.
* **풀 크기는 의도적으로 정합니다.** 모든 프레임워크는 프로세스마다 풀을 엽니다. 숫자를 고르기 전에 프로세스 수를 곱하세요. [연결 풀링](https://villagesql.com/docs/ko/guides/connection-pooling.md)을 참고하세요.

## Django

```python theme={null}
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myapp",
        "USER": "app",
        "PASSWORD": environ["DB_PASSWORD"],
        "HOST": "127.0.0.1",
        "PORT": "3306",
        "OPTIONS": {
            "charset": "utf8mb4",
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}
```

Django 관련 참고 사항:

* Django 문서가 권장하는, 유지 관리되는 C 드라이버인 `mysqlclient`를 사용하세요.
* Django는 일부 제약 조건을 Python에서 흉내 냅니다. 실제 데이터베이스 제약 조건도 추가하세요(`unique=True`는 실제 고유 인덱스가 되지만, 검사 제약 조건은 `Meta`에 `CheckConstraint`가 필요합니다).
* `select_related()`(JOIN)와 `prefetch_related()`(두 번째 쿼리)가 N+1 도구입니다. 언제 쓰는지는 아래를 참고하세요.

## Rails

```yaml theme={null}
# config/database.yml
production:
  adapter: mysql2
  database: myapp
  username: app
  password: <%= ENV["DB_PASSWORD"] %>
  host: 127.0.0.1
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```

Rails 관련 참고 사항:

* `database.yml`의 `encoding: utf8mb4`는 연결 문자 집합과 `rails db:create`의 기본값을 모두 설정합니다.
* ActiveRecord 유효성 검사(`validates_uniqueness_of`)는 동시성 아래에서 경쟁 상태가 됩니다. 모든 고유성 검사를 실제 고유 인덱스로 뒷받침하고, [1062 중복 키 오류](https://villagesql.com/docs/ko/guides/common-mysql-errors.md)가 마지막 방어선이 되게 하세요.
* `includes`가 N+1 도구입니다. `strict_loading` 모드는 지연 로딩을 오류로 바꾸어 N+1이 배포되는 대신 개발 중에 실패하게 합니다.
* Rails 8.1은 이전 버전이 `pool`을 생성하던 자리에 `database.yml`에 `max_connections`를 생성합니다. `pool:` 키는 `max_connections`가 읽는 대체값으로 여전히 조용히 동작합니다. 둘을 서로 다른 값으로 설정하면 부팅 시 예외가 발생합니다. Rails 8이 더 이상 MySQL을 기본값으로 하지 않아 필요한 `--database=mysql` 플래그를 포함한 전체 앱은 [Rails 8로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/rails-mysql.md)를 참고하세요.

## Prisma

```prisma theme={null}
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}
```

```text theme={null}
DATABASE_URL="mysql://app:password@127.0.0.1:3306/myapp?connection_limit=10"
```

Prisma 관련 참고 사항:

* Prisma는 기본적으로 utf8mb4를 사용합니다. 주의할 설정은 URL의 `connection_limit`이며, 기본값이 낮습니다.
* `prisma migrate`는 스키마 드리프트에서 DDL을 생성합니다. 직접 작성한 마이그레이션과 똑같이, 프로덕션에 적용하기 전에 생성된 SQL을 읽으세요. [스키마 마이그레이션](https://villagesql.com/docs/ko/guides/schema-migrations.md)을 참고하세요.
* 관계 쿼리는 `include`를 사용합니다. 결과를 반복하며 관계를 하나씩 접근할 때 N+1 형태가 나타납니다.
* Prisma 7은 위의 연결 URL을 `schema.prisma` 밖의 별도 설정 파일로 옮기고, 연결에 드라이버 어댑터를 요구합니다. 전체 Prisma 7 앱은 [Next.js와 Prisma로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/mysql-with-prisma.md)를 참고하세요.

## N+1 문제, 한 번에 정리

보편적인 ORM 성능 버그: 주문 100개를 로드한 뒤 각 주문의 고객을 지연 로드하면 ORM은 쿼리 101개를 실행합니다. 해결책은 모든 프레임워크에서 같은 아이디어입니다. 필요한 관계를 미리 선언해 ORM이 한두 개의 쿼리로 가져오게 하세요(`select_related` / `includes` / `include`). 탐지 도구도 보편적입니다: 개발 환경에서 쿼리 로깅을 켜고 ORM이 실제로 보내는 것을 읽거나, 프로덕션에서 [슬로 쿼리 로그](https://villagesql.com/docs/ko/guides/slow-query-log.md)를 지켜보세요.

## SQL로 내려가야 할 때

ORM은 CRUD에서 제값을 하고 분석에서는 그렇지 못합니다. 윈도우 함수, CTE, 대량 업서트, 다중 테이블 보고 쿼리는 그것을 표현하려 애쓰는 쿼리 빌더 체인보다 SQL에서 더 명확합니다. 모든 ORM에는 탈출구가 있습니다(Django의 `raw()`, Rails의 `find_by_sql`, Prisma의 `$queryRaw`). 그럴 가치가 있는 5퍼센트의 쿼리에 그것을 쓰는 것은 패배가 아니라 좋은 엔지니어링입니다. 이것은 또한 VillageSQL 확장 함수가 ORM 애플리케이션에 도달하는 방법이기도 합니다: `SELECT UUID_V7()`이나 `ai_prompt(...)`는 이 탈출구 중 어느 것을 통해서든 동작합니다. ORM은 SQL을 그대로 통과시킬 뿐이기 때문입니다.

## 함께 보기

* [Next.js와 Prisma로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/mysql-with-prisma.md) — 설정만이 아닌, Prisma 7 위의 전체 앱
* [Next.js와 Drizzle로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/mysql-with-drizzle.md) — 위에서 다루지 않은, 더 가볍고 SQL 우선인 대안 Drizzle 위의 전체 앱
* [Next.js로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/nextjs-mysql.md) — ORM 없이 연결 설정과 쿼리 패턴
* [Rails 8로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/rails-mysql.md) — Rails 8이 MySQL을 고르기 위해 필요한 스캐폴드 플래그를 포함한 전체 앱
* [Laravel 12로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/laravel-mysql.md) — 위에서 다루지 않은, Laravel의 Eloquent ORM 위의 전체 앱
* [Go와 sqlc로 MySQL 사용하기](https://villagesql.com/docs/ko/guides/go-sqlc-mysql.md) — 런타임 ORM 대신 생성된 타입 안전 쿼리
* [연결 풀링](https://villagesql.com/docs/ko/guides/connection-pooling.md) — 프로세스에 걸친 풀 크기 정하기
* [utf8mb4와 이모지](https://villagesql.com/docs/ko/guides/utf8mb4.md) — 위의 모든 설정이 지정하는 문자 집합 설정
* [슬로 쿼리 로그](https://villagesql.com/docs/ko/guides/slow-query-log.md) — ORM이 생성하는 것 잡아내기
* [스키마 마이그레이션](https://villagesql.com/docs/ko/guides/schema-migrations.md) — ORM이 생성한 DDL을 안전하게 적용하기


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.