JavaScript 데이터베이스 통합: 원활한 데이터 관리와 성능을 위한 8가지 필수 메서드

발행: (2025년 12월 11일 오후 08:48 GMT+9)
4 min read
원문: Dev.to

Source: Dev.to

풀(Pool)로 데이터베이스 연결 관리하기

요청마다 새 연결을 만드는 것은 느리고 비효율적입니다. 연결 풀은 사용 가능한 연결을 미리 만들어 두었다가 체크아웃하고 사용한 뒤 다시 풀에 반환할 수 있게 합니다.

import mysql from 'mysql2/promise';

class DatabasePool {
  constructor() {
    this.pool = mysql.createPool({
      host: 'localhost',
      user: 'app_user',
      password: 'secure_password',
      database: 'my_app_db',
      waitForConnections: true,
      connectionLimit: 20,
      queueLimit: 0
    });
  }

  async query(sql, values) {
    let connection;
    try {
      connection = await this.pool.getConnection();
      const [results] = await connection.execute(sql, values);
      return results;
    } catch (err) {
      console.error('Database query failed:', err.message);
      // Add retry logic for specific errors if needed
      throw err;
    } finally {
      if (connection) connection.release();
    }
  }
}

export default new DatabasePool();

객체 지향 데이터 접근을 위한 ORM 사용

객체‑관계 매퍼(ORM)를 사용하면 데이터베이스 행을 JavaScript 객체와 클래스 형태로 다룰 수 있어, 순수 SQL 문자열을 직접 작성할 필요가 줄어듭니다.

// user.model.js
import { Model, DataTypes } from 'sequelize';
import sequelize from '../config/database.js';
import Post from './post.model.js';

class User extends Model {}

User.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true,
    validate: { isEmail: true }
  },
  fullName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  isActive: {
    type: DataTypes.BOOLEAN,
    defaultValue: true
  }
}, {
  sequelize,
  modelName: 'User',
  tableName: 'users'
});

// Relationships
User.hasMany(Post, { foreignKey: 'authorId' });
Post.belongsTo(User, { foreignKey: 'authorId' });

export default User;

예시 작업

// Create a new user
const newUser = await User.create({
  email: 'hello@example.com',
  fullName: 'Jane Developer'
});
console.log(newUser.id);

// Find a user with their posts
const user = await User.findOne({
  where: { email: 'hello@example.com' },
  include: Post
});
console.log(user.fullName);
user.Posts.forEach(post => console.log(post.title));

// Update a user
await user.update({ isActive: false });

유연하고 안전한 SQL 생성을 위한 Query Builder

ORM이 너무 무겁게 느껴질 때, 쿼리 빌더는 체이닝 가능한 API를 제공해 파라미터화된 SQL을 생성하고, 인젝션 공격을 방지합니다.

import knex from 'knex';

const db = knex({
  client: 'mysql2',
  connection: {
    host: 'localhost',
    user: 'app_user',
    password: 'secure_password',
    database: 'my_app_db'
  }
});

// Dynamic user search
async function searchUsers(filters = {}) {
  let query = db('users')
    .select('id', 'fullName', 'email', 'created_at');

  if (filters.name) {
    query = query.where('fullName', 'like', `%${filters.name}%`);
  }
  if (filters.active !== undefined) {
    query = query.where('isActive', filters.active);
  }
  if (filters.minDate) {
    query = query.where('created_at', '>=', filters.minDate);
  }

  return await query
    .orderBy('created_at', 'desc')
    .limit(50);
}

// Usage
const activeUsers = await searchUsers({ active: true, name: 'Jane' });

마이그레이션으로 스키마 변경 관리하기

마이그레이션은 버전‑관리된 스크립트를 제공해 데이터베이스 스키마를 안전하게 진화시킬 수 있게 합니다.

// migrations/20230915_add_bio_to_users.js
export async function up(knex) {
  await knex.schema.table('users', (table) => {
    table.text('bio').nullable().after('fullName'); // Add column
    table.index(['isActive'], 'idx_users_active');   // Add index
  });
}

export async function down(knex) {
  await knex.schema.table('users', (table) => {
    table.dropIndex('idx_users_active');
    table.dropColumn('bio');
  });
}

마이그레이션을 실행하면 새로운 컬럼과 인덱스가 적용되고, 롤백하면 변경 사항이 되돌아갑니다.

영속화 전 데이터 검증하기

데이터베이스에 도달하기 전에 JavaScript에서 입력을 검증하면 더 명확한 오류 메시지를 제공하고 비즈니스 규칙을 초기에 강제할 수 있습니다.

import Joi from 'joi';

const userSchema = Joi.object({
  email: Joi.string().email().required(),
  fullName: Joi.string().min(2).max(100).required(),
  age: Joi.number().integer().min(13).max(120).optional(),
  website: Joi.string().uri().allow('').optional()
});

레코드를 생성하거나 업데이트하기 전에 userSchema.validate(data)(또는 validateAsync)를 사용하세요.

Back to Blog

관련 글

더 보기 »

Dev 커뮤니티 신규 회원

여러분 안녕하세요, 저는 dev 커뮤니티에 새로 온 사람이고 코딩 여정을 다시 시작하고 있습니다. 저는 2013년부터 2018년까지 코딩을 했었습니다. 그 이후에 새로운 기회를 탐색했고, st...