
Linkコンポーネントによる画面遷移
はじめに 前回までにNext.jsのページコンポーネント作成方法を学びました。今回は、作成したページ間をシームレスに移動するための「Linkコンポーネント」につ […]
このガイドでは、Node.jsアプリケーションからmysql2パッケージを使ってMySQLデータベースに接続する方法を、基礎から実践まで詳しく解説します。
mysql2はNode.js用の高性能MySQLクライアントで、以下の特徴があります:
npm install mysql2
# または
yarn add mysql2
npm install --save-dev @types/node typescript
# tsconfig.jsonを作成
npx tsc --init
DB_HOST=localhost
DB_PORT=3306
DB_USER=your_username
DB_PASSWORD=your_password
DB_NAME=your_database
// db.js
const mysql = require('mysql2/promise');
require('dotenv').config();
async function createConnection() {
return await mysql.createConnection({
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
}
module.exports = { createConnection };
// testConnection.js
const { createConnection } = require('./db');
(async () => {
let connection;
try {
connection = await createConnection();
console.log('MySQLに接続しました');
// 簡単なクエリの実行
const [rows] = await connection.query('SELECT 1 + 1 AS result');
console.log('1 + 1 =', rows[0].result);
} catch (error) {
console.error('接続エラー:', error);
} finally {
if (connection) await connection.end();
console.log('接続を閉じました');
}
})();
実運用では接続プールを使用するのがベストプラクティスです。
// pool.js
const mysql = require('mysql2/promise');
require('dotenv').config();
const pool = mysql.createPool({
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = pool;
const pool = require('./pool');
async function getUsers() {
const [rows] = await pool.query('SELECT * FROM users LIMIT 10');
return rows;
}
async function getUserById(id) {
const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
return rows[0] || null;
}
SQLインジェクション対策に必須です。
async function createUser(userData) {
const sql = 'INSERT INTO users (name, email, age) VALUES (?, ?, ?)';
const [result] = await pool.execute(sql, [
userData.name,
userData.email,
userData.age
]);
return result.insertId;
}
async function getUsersByIds(ids) {
const sql = 'SELECT * FROM users WHERE id IN (?)';
const [rows] = await pool.query(sql, [ids]);
return rows;
}
// 実際には以下のように使用
// await getUsersByIds([1, 2, 3]);
async function transferMoney(fromId, toId, amount) {
const conn = await pool.getConnection();
try {
await conn.beginTransaction();
// 送金元の残高を減らす
await conn.query(
'UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?',
[amount, fromId, amount]
);
// 送金先の残高を増やす
await conn.query(
'UPDATE accounts SET balance = balance + ? WHERE id = ?',
[amount, toId]
);
// トランザクションをコミット
await conn.commit();
return true;
} catch (error) {
await conn.rollback();
console.error('Transfer failed:', error);
return false;
} finally {
conn.release();
}
}
MySQLエラーを適切に処理する方法:
async function safeQuery(sql, params) {
try {
const [rows] = await pool.query(sql, params);
return { success: true, data: rows };
} catch (error) {
console.error('Database error:', {
sql,
params,
errorCode: error.code,
errno: error.errno,
sqlState: error.sqlState,
sqlMessage: error.sqlMessage
});
// アプリケーション固有のエラーに変換
if (error.code === 'ER_DUP_ENTRY') {
return { success: false, error: 'Duplicate entry' };
}
if (error.code === 'ER_NO_REFERENCED_ROW_2') {
return { success: false, error: 'Foreign key constraint fails' };
}
return { success: false, error: 'Database operation failed' };
}
}
const pool = mysql.createPool({
// ...他の設定
connectionLimit: 20, // 最大接続数
idleTimeout: 60000, // アイドル接続のタイムアウト(ms)
enableKeepAlive: true, // 接続を維持
keepAliveInitialDelay: 0, // キープアライブの初期遅延
connectTimeout: 10000, // 接続タイムアウト(ms)
queueLimit: 0 // 接続待ちキューの制限(0 = 無制限)
});
async function getPaginatedUsers(page = 1, pageSize = 10) {
const offset = (page - 1) * pageSize;
const [rows] = await pool.query(
'SELECT id, name, email FROM users ORDER BY id LIMIT ? OFFSET ?',
[pageSize, offset]
);
return rows;
}
解決策:
const pool = mysql.createPool({
// ...他の設定
connectTimeout: 10000, // 10秒
});
解決策 (キープアライブを有効化):
const pool = mysql.createPool({
// ...他の設定
enableKeepAlive: true,
keepAliveInitialDelay: 0
});
MySQL 8.0の認証方式変更によるエラー:
解決策:
-- MySQLで実行
ALTER USER 'your_username'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
FLUSH PRIVILEGES;
// userRepository.js
const pool = require('./pool');
class UserRepository {
async findAll() {
const [rows] = await pool.query('SELECT * FROM users');
return rows;
}
async findById(id) {
const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [id]);
return rows[0];
}
async create(user) {
const [result] = await pool.query(
'INSERT INTO users (name, email, password_hash) VALUES (?, ?, ?)',
[user.name, user.email, user.passwordHash]
);
return result.insertId;
}
async update(id, userData) {
const [result] = await pool.query(
'UPDATE users SET name = ?, email = ? WHERE id = ?',
[userData.name, userData.email, id]
);
return result.affectedRows > 0;
}
async delete(id) {
const [result] = await pool.query('DELETE FROM users WHERE id = ?', [id]);
return result.affectedRows > 0;
}
}
module.exports = new UserRepository();
// app.js
const express = require('express');
const userRepository = require('./userRepository');
const app = express();
app.use(express.json());
app.get('/users', async (req, res) => {
try {
const users = await userRepository.findAll();
res.json(users);
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
app.get('/users/:id', async (req, res) => {
try {
const user = await userRepository.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
// 他のルートも同様に実装...
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
このガイドで、Node.jsからmysql2パッケージを使ってMySQLデータベースに接続する方法を包括的に学びました。実際のプロジェクトでは、要件に応じてさらに最適化を加えてください。