JavaScript 数据库集成:8 个实现无缝数据管理和性能的关键方法

发布: (2025年12月11日 GMT+8 19:48)
4 min read
原文: Dev.to

Source: Dev.to

使用连接池管理数据库连接

为每个请求创建新连接既慢又浪费资源。连接池维护一组随时可用的连接,能够被取出、使用,然后再释放回池中。

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 构造

当 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 社区的新成员,重新开始我的 coding 之旅。我曾在 2013‑2018 年间编写代码。之后我探索了新的机会,...