Rust에서 데이터베이스를 사용하려면? Diesel을 소개합니다
Rust는 성능과 안전성을 제공하는 시스템 프로그래밍 언어이지만, 웹 개발이나 애플리케이션 개발 시 데이터베이스 연동도 필수적입니다. Rust에서 가장 널리 사용되는 ORM(Object Relational Mapping) 도구 중 하나는 Diesel입니다.
Diesel은 Rust스러운 타입 안정성과 컴파일 타임 검사를 제공하여 런타임 에러를 줄이고 생산성을 높여줍니다. 이 글에서는 Diesel을 사용해 PostgreSQL 데이터베이스에 연결하고, 간단한 CRUD 예제를 구현해 보겠습니다.
환경 준비: Diesel 설치 및 설정
먼저, Diesel CLI를 설치하고 프로젝트를 초기화해야 합니다.
$ cargo install diesel_cli --no-default-features --features postgres
Diesel CLI는 마이그레이션 관리 및 데이터베이스 초기화를 도와주는 도구입니다. PostgreSQL을 사용하므로 해당 feature를 명시합니다.
다음으로, Cargo.toml 파일에 필요한 의존성을 추가합니다.
[dependencies]
diesel = { version = "2.1", features = ["postgres"] }
dotenvy = "0.15"
dotenvy
는 .env
파일에 설정된 DB 정보를 읽기 위해 사용됩니다.
데이터베이스 초기화 및 마이그레이션
Diesel CLI를 사용해 데이터베이스를 초기화합니다.
$ diesel setup
그 전에 .env
파일을 생성하고 다음 내용을 추가합니다:
DATABASE_URL=postgres://postgres:password@localhost/mydb
그리고 Diesel 마이그레이션을 생성합니다:
$ diesel migration generate create_users
마이그레이션 폴더에 생성된 up.sql과 down.sql 파일에 아래 SQL을 작성합니다:
-- up.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);
-- down.sql
DROP TABLE users;
마이그레이션 적용:
$ diesel migration run
스키마 및 모델 정의
Diesel은 Rust 코드와 DB 스키마를 연결하기 위해 매크로 기반 구조를 사용합니다. 먼저 schema.rs
를 자동 생성합니다.
$ diesel print-schema > src/schema.rs
이제 models.rs 파일에 사용자 모델을 정의합니다.
use diesel::prelude::*;
use crate::schema::users;
#[derive(Queryable)]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
}
#[derive(Insertable)]
#[diesel(table_name = users)]
pub struct NewUser<'a> {
pub name: &'a str,
pub email: &'a str,
}
DB 연결 설정 및 삽입 함수 작성
DB 연결 및 삽입 기능을 main.rs
에 작성해보겠습니다.
mod schema;
mod models;
use diesel::prelude::*;
use dotenvy::dotenv;
use std::env;
use models::{User, NewUser};
fn establish_connection() -> PgConnection {
dotenv().ok();
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL not set");
PgConnection::establish(&db_url).expect("DB 연결 실패")
}
fn create_user(conn: &mut PgConnection, name: &str, email: &str) -> User {
use schema::users;
let new_user = NewUser { name, email };
diesel::insert_into(users::table)
.values(&new_user)
.returning((users::id, users::name, users::email))
.get_result(conn)
.expect("삽입 실패")
}
fn main() {
let mut conn = establish_connection();
let user = create_user(&mut conn, "Alice", "alice@example.com");
println!("새 사용자: {} ({})", user.name, user.email);
}
전체 프로젝트 구조 요약
├── src
│ ├── main.rs
│ ├── models.rs
│ ├── schema.rs
├── migrations
│ ├── create_users/
│ ├── up.sql
│ ├── down.sql
├── .env
├── Cargo.toml
이 구조는 Diesel과 PostgreSQL을 사용한 Rust 프로젝트의 기본 뼈대입니다.
결론: Rust에서 안전하게 DB 다루기
Diesel은 Rust의 타입 시스템을 활용하여 런타임 에러를 컴파일 타임에 잡을 수 있는 ORM입니다. 마이그레이션 시스템, 쿼리 빌더, 자동 스키마 생성을 통해 효율적이고 안전한 데이터베이스 연동이 가능합니다.
이 글에서 살펴본 예제는 기본적인 CRUD 중 생성(Create)에 해당하며, 이후 조회(Read), 수정(Update), 삭제(Delete)도 Diesel의 쿼리 빌더 문법을 통해 간단히 구현할 수 있습니다.
실전 웹 개발에서는 actix-web
또는 axum
같은 웹 프레임워크와 함께 사용하면 강력한 백엔드 API를 구성할 수 있습니다.