๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ‘จ‍๐Ÿ’ป web.dev/node

Node.js์™€ MySQL๋ฅผ ์ด์šฉํ•œ ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑํ•˜๊ธฐ ํŠœํ† ๋ฆฌ์–ผ

by HandHand 2021. 3. 5.

MySQL ์—ฐ๋™ ๋ฐฉ๋ฒ•

Node.js ์—์„œ MySQL์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Sequelize ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ
์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” raw query๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ mysql์„ ์—ฐ๋™ํ•˜๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ

mysql ์ ‘์†

ํ„ฐ๋ฏธ๋„์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•œ ๋’ค ์•”ํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  DB์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.

$ mysql -u root -p

database ๋ฐ table ์ƒ์„ฑ

๋ฐ๋ชจ๋ฅผ ์œ„ํ•ด tutorial ์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

mysql> create database tutorial;

๊ทธ๋ฆฌ๊ณ  tutorial ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฒŒ์‹œ๊ธ€ ์ •๋ณด๋ฅผ ๋‹ด์„ board ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

mysql> use tutorial;
mysql> create table board (
        idx int unsigned not null primary key auto_increment,
        creator_id varchar(100) not null,
        title varchar(100) not null,
        content MEDIUMTEXT not null,
        passwd varchar(100) not null,
        hit int unsigned not null default 0
      );

์ดํ›„ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ž„์˜์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ 2๊ฐœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

mysql> insert into board(
  creator_id, title, content, passwd, hit) values
  ('simpson', 'tutorial blog', 'hello', '1234', 0), ('bart', 'another blog', 'hello', '1234', 0);

๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅ๋˜์—ˆ๋Š”์ง€ SELECT ๋ฌธ์„ ํ†ตํ•ด ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

mysql> select * from board;
+-----+------------+---------------+---------+--------+-----+
| idx | creator_id | title         | content | passwd | hit |
+-----+------------+---------------+---------+--------+-----+
|   3 | simpson    | tutorial blog | hello   | 1234   |   0 |
|   4 | bart       | another blog  | hello   | 1234   |   0 |
+-----+------------+---------------+---------+--------+-----+

Node.js ์„ค์ •

mysql ํŒจํ‚ค์ง€ ์„ค์น˜

$ npm i mysql

database.js ์ƒ์„ฑ

Node.js์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์—ฐ๋™ํ•˜๊ธฐ ์œ„ํ•ด config ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ ๋‹ค์Œ,
๊ทธ ์•ˆ์— database.js ๋ฅผ ๋งŒ๋“ค์–ด ํ•„์š”ํ•œ ์„ค์ •์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
init ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด Connection ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹ค์ œ ์—ฐ๊ฒฐ์€ connect ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

config/database.js

const mysql = require("mysql");

const db_config = {
  host: "localhost",
  port: "3306",
  user: "root",
  password: "๋น„๋ฐ€๋ฒˆํ˜ธ",
  database: "tutorial",
};

module.exports = () => {
  return {
    init() {
      return mysql.createConnection(db_config);
    },
    test_connection(con) {
      con.connect((err) => {
        if (err) {
          console.error("mysql connection error : " + err);
        } else {
          console.log("mysql connected successfully!");
        }
      });
    },
  };
};

์‹ค์ œ ์ฟผ๋ฆฌ๋Š” ์ด๋ฃจ์–ด์ง€์ง€ ์•Š์ง€๋งŒ ์„œ๋ฒ„ ์‹คํ–‰์‹œ MySQL์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด

app.js ์—์„œ test_connection ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

app.js

// ... ์ค‘๋žต
const db_config = require("./config/database")();

const app = express();

// database connection
const connection = db_config.init();
db_config.test_connection(connection);

์‹คํ–‰

์„ค์ •์„ ๋งˆ์ณค๋‹ค๋ฉด npm start ๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋ฅผ ์‹คํ–‰์‹œ์ผœ๋ด…๋‹ˆ๋‹ค.
๋งŒ์•ฝ mysql 8 ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ด ๊ธ€์„ ์ž‘์„ฑํ–ˆ๋˜ 2020๋…„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

mysql connection error : Error: ER_NOT_SUPPORTED_AUTH_MODE:
Client does not support authentication protocol requested by server;
consider upgrading MySQL client

์ด ๊ฒฝ์šฐ์—๋Š” ํ„ฐ๋ฏธ๋„์„ ์—ด๊ณ  mysql์— ์ ‘์†ํ•œ ๋’ค ๋‹ค์Œ๊ณผ ๊ฐ™์ด mysql8 ๊ถŒํ•œ ์„ค์ •์„ ๋ณ€๊ฒฝํ•ด์ค๋‹ˆ๋‹ค.

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_new_password';
mysql> FLUSH PRIVILEGES;

ํ•ด๋‹น ์˜ค๋ฅ˜์™€ ๊ด€๋ จ๋œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ์˜ stack overflow ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์™œ ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ?

์งง๊ฒŒ ์š”์•ฝํ•˜๋ฉด `mysql 8` ๋ถ€ํ„ฐ ์•”ํ˜ธํ™” ๋ฐฉ๋ฒ•์ด ๋ฐ”๋€Œ์–ด `caching_sha2_password` ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ,
์šฐ๋ฆฌ๊ฐ€ ๋‹ค์šด๋ฐ›์€ `mysql` ํŒจํ‚ค์ง€๊ฐ€ ํ•ด๋‹น ์•”ํ˜ธํ™” ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

๊ฒŒ์‹œ๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

์ด์ œ ๋ผ์šฐํ„ฐ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด์„œ ์ฟผ๋ฆฌ๋ฌธ์„ ํ†ตํ•ด board ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
routes ๋””๋ ‰ํ† ๋ฆฌ์˜ index.js์—์„œ ๋ฉ”์ธ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด์ค„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌ๋ฌธ์„ ํ†ตํ•ด ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

routes/index.js

const express = require("express");
const db_config = require("../config/database")();

const router = express.Router();

// database connection
const connection = db_config.init();
connection.connect();

/* GET home page. */
router.get("/", function (req, res, next) {
  const qry = "SELECT * FROM board";
  connection.query(qry, (err, rows) => {
    if (err) {
      console.error("query error" + err);
      res.status(500).send("Internal Server Error");
    } else {
      res.render("index", { title: "MySQL ์—ฐ๋™ ๋ฐ๋ชจ", rows: rows });
    }
  });
});

module.exports = router;

connection ๊ฐ์ฒด์˜ query ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์›ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์„ ์ง€์ •ํ•ด์„œ ํ˜ธ์ถœํ•˜๋ฉด
๋“ฑ๋ก๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์›น ํŽ˜์ด์ง€์—์„œ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด index.ejs๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
(ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์‹œ ํ…œํ”Œ๋ฆฟ ์—”์ง„์€ ejs ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.)

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel="stylesheet" href="/stylesheets/style.css" />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>

    <% for(let row of rows) { %>
    <p><%= row.idx%></p>
    <p><%= row.creator_id%></p>
    <p><%= row.title%></p>
    <p><%= row.content%></p>
    <p><%= row.regdate%></p>
    <hr />
    <% } %>
  </body>
</html>

์‹คํ–‰ ๊ฒฐ๊ณผ

์ด์ œ ์„œ๋ฒ„๋ฅผ ๋‹ค์‹œ ์ผœ๊ณ  ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ ‘์†ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

๐Ÿ’ฌ ๋Œ“๊ธ€