Prisma
TypeScript/Node.js용 ORM. 스키마 파일로 DB 구조를 정의하고, 타입 안전한 쿼리 클라이언트를 자동 생성한다.
구성 요소
| 구성 | 역할 |
|---|---|
prisma/schema.prisma |
데이터 모델 정의 |
prisma/migrations/ |
마이그레이션 파일 |
@prisma/client |
자동 생성되는 쿼리 클라이언트 |
스키마 작성
// prisma/schema.prisma
datasource db {
provider = "mysql" // mysql | postgresql | sqlite
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
createdAt DateTime @default(now())
orders Order[]
}
model Order {
id Int @id @default(autoincrement())
total Int
status String @default("pending")
userId Int
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}CLI 명령어
npx prisma init # 초기화 (schema.prisma 생성)
npx prisma generate # Client 재생성 (스키마 변경 후)
npx prisma migrate dev # 마이그레이션 생성 + 적용 (개발)
npx prisma migrate deploy # 마이그레이션 적용 (프로덕션)
npx prisma migrate reset # DB 초기화 + 마이그레이션 재적용
npx prisma db push # 마이그레이션 없이 스키마 동기화 (프로토타이핑)
npx prisma db seed # 시드 데이터 삽입
npx prisma studio # GUI 데이터 브라우저 (localhost:5555)쿼리 예시
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// 단건 조회
const user = await prisma.user.findUnique({ where: { id: 1 } })
// 목록 조회
const users = await prisma.user.findMany({
where: { name: { contains: '김' } },
orderBy: { createdAt: 'desc' },
take: 10,
skip: 0,
})
// 관계 포함 조회
const userWithOrders = await prisma.user.findUnique({
where: { id: 1 },
include: { orders: true },
})
// 생성
const newUser = await prisma.user.create({
data: { email: 'test@example.com', name: '김탄' },
})
// 수정
await prisma.user.update({
where: { id: 1 },
data: { name: '이름변경' },
})
// 삭제
await prisma.user.delete({ where: { id: 1 } })
// 집계
const count = await prisma.user.count()
const stats = await prisma.order.aggregate({
_sum: { total: true },
_avg: { total: true },
where: { status: 'paid' },
})트랜잭션
// 순차 실행 (각 쿼리가 독립적)
await prisma.$transaction([
prisma.user.update({ where: { id: 1 }, data: { name: 'A' } }),
prisma.order.create({ data: { total: 1000, userId: 1 } }),
])
// 인터랙티브 트랜잭션 (이전 결과 참조 가능)
await prisma.$transaction(async (tx) => {
const user = await tx.user.findUnique({ where: { id: 1 } })
await tx.order.create({ data: { total: 1000, userId: user.id } })
}).env 설정
# 기본
DATABASE_URL="mysql://user:password@localhost:3306/dbname"
# TCP 연결 강제 (Unix socket 우회) — 아래 참고
DATABASE_URL="mysql://user:password@127.0.0.1:3306/dbname?prefer_socket=false"localhost vs 127.0.0.1 (Unix Socket 이슈)
mysql2는 host=localhost 지정 시 TCP 대신 Unix Domain Socket(/var/run/mysqld/mysqld.sock)으로 연결을 시도한다. IP 서버에 연결해야 하는데 로컬로 연결되거나 소켓 파일을 찾지 못해 실패하는 경우 두 가지 방법 중 하나로 해결한다.
| 방법 | 예시 |
|---|---|
prefer_socket=false 추가 |
mysql://user:pass@localhost:3306/db?prefer_socket=false |
host를 127.0.0.1로 변경 |
mysql://user:pass@127.0.0.1:3306/db |
Unix socket을 의도적으로 사용하는 경우, ?socket=에 소켓 파일 전체 경로를 지정한다 (지정 시 host/port는 무시됨).
DATABASE_URL="mysql://user:pass@localhost/dbname?socket=/var/run/mysqld/mysqld.sock"