
지금까지는 변수에 모든 데이터를 저장.
- 서버 종료시 메모리 정리 → 변수에 저장된 데이터도 사라짐
DB를 이용하면, 서버가 종료되어도 데이터가 사라지지 않게 할 수 있음.
DataBase
DataBase Management System(DBMS)
MySQL 설치
MySQL :: Download MySQL Installer
MySQL Installer 8.0.44 Note: MySQL 8.0 is the final series with MySQL Installer. As of MySQL 8.1, use a MySQL product's MSI or Zip archive for installation. MySQL Server 8.1 and higher also bundle MySQL Configurator, a tool that helps configure MySQL Serve
dev.mysql.com
$ mysql -h [접속할 주소] -u [사용자 이름] -p

mysql> exit
MySQL Workbench
MySQL :: Download MySQL Workbench
dev.mysql.com





1) SQL
2) 데이터베이스(DB, SCHEMA) 생성
$ mysql -h [접속할 주소] -u [사용자 이름] -p
CREATE SCHEMA [데이터베이스명];
CREATE SCHEMA [데이터베이스명] DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
use [데이터베이스명];
3) 테이블 생성
mysql> CREATE TABLE [DB명.테이블명] (
-> [컬럼명] [자료형_type] [옵션],
-> . . .
-> [컬럼명] [자료형_type] [옵션])
-> COMMENT = '테이블 보충 설명'
-> ENGINE = InnoDB; -- MyISAM 과 InnoDB를 주로 이용
Query OK, 0 row affected (0.09 sec)
mysql> CREATE TABLE nodejs.users (
-> id INT NOT NULL AUTO_INCREMENT,
-> name VARCHAR(20) NOT NULL,
-> age INT UNSIGNED NOT NULL,
-> married TINYINT NOT NULL,
-> comment TEXT NULL,
-> created_at DATETIME NOT NULL DEFAULT now(),
-> PRIMARY KEY(id),
-> UNIQUE INDEX name_UNIQUE (name ASC))
-> COMMENT = '사용자 정보'
-> ENGINE = InnoDB;
Query OK, 0 row affected (0.09 sec)
4) 컬럼
mysql> CREATE TABLE nodejs.users (
-> id INT NOT NULL AUTO_INCREMENT, --[컬럼명] [자료형_type] [옵션]
-> name VARCHAR(20) NOT NULL,
-> age INT UNSIGNED NOT NULL,
-> married TINYINT NOT NULL,
-> comment TEXT NULL,
-> created_at DATETIME NOT NULL DEFAULT now(),
-> PRIMARY KEY(id),
-> UNIQUE INDEX name_UNIQUE (name ASC));
5) 테이블 설정
mysql> COMMENT = '사용자 정보'
-> ENGINE = InnoDB;
6) 테이블 조회
mysql> DESC [테이블명];

7) 테이블 삭제
mysql> DROP TABLE [테이블 명];
8) 외래키(foregn key)
mysql> CREATE TABLE nodejs.comments (
-> id INT NOT NULL AUTO_INCREMENT,
-> commenter INT NOT NULL, -- users의 id정보를 담음
-> comment VARCHAR(100) NOT NULL,
-> created_at DATETIME NOT NULL DEFAULT now(),
-> PRIMARY KEY(id),
-> INDEX commenter_idx (commenter ASC),
-> CONSTRAINT commenter
-> FOREIGN KEY (commenter)
-> REFERENCES nodejs.users (id)
-> ON DELETE CASCADE
-> ON UPDATE CASCADE)
-> COMMENT = '댓글'
-> ENGINE=InnoDB;
Query OK, 0 row affected (0.09 sec)
mysql> CREATE TABLE nodejs.comments (
-> ...
-> commenter INT NOT NULL,
-> ...
-> INDEX commenter_idx (commenter ASC),
-> -- CONSTRAINT [제약조건명] FOREIGN KEY [컬럼명] REFERENCES [참고하는 컬럼명]
-> CONSTRAINT commenter --[제약조건명]
-> FOREIGN KEY (commenter) --[컬럼명]
-> REFERENCES nodejs.users (id)--[참고하는 컬럼명]
-> ON DELETE CASCADE
-> ON UPDATE CASCADE
-> )
9) DB 내부의 테이블 조회
mysql> SHOW TABLES;

1. 데이터베이스 생성



** 이미 콘솔로 nodejs라는 Schema를 생성해, 같은 이름의 schema를 생성할 수 없어,
워크벤치로는 nodejswb라는 이름으로 생성함.
2. 테이블 생성



3) 외래키 지정

1) Create
mysql> INSERT INTO [DB명].[테이블명] (col1, col2, ... , colN) VALUES ( val1 , val2, . . ., valN );
mysql> INSERT INTO nodejs.users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개1');
mysql> INSERT INTO nodejs.users (name, age, married, comment) VALUES ('nero', 32,1, '자기소개2');
mysql> INSERT INTO nodejs.comments (commenter, comment) VALUES (1, '안녕하세요. zero의 댓글입니다');


2) Read
mysql> SELECT [조회하려는 컬럼명] FROM [테이블명];

mysql> SELECT [조회하려는 컬럼명] FROM [테이블명] WHERE [조건절];

mysql> SELECT [조회하려는 컬럼명] FROM [테이블명] ORDER BY [컬럼명] [ASC|DESC];

mysql> SELECT [조회하려는 컬럼명] FROM [테이블명] LIMIT [숫자];

mysql> SELECT [조회하려는 컬럼명] FROM [테이블명] LIMIT [숫자] OFFSET [건너뛸 숫자];

3) Update
mysql> UPDATE [테이블명] SET [컬럼명=바꿀 값] WHERE [조건]

4) Delete
mysql> DELETE FROM [테이블명] WHERE [조건]


1) 데이터 베이스 연결
// app.js
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const nunjucks = require('nunjucks');
const { sequelize } = require('./models');
const app = express();
app.set('port', process.env.PORT || 3001);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
sequelize.sync({ force: false }) // 서버 실행시 MySQL과 연동되도록 함
.then(() => {
console.log('데이터베이스 연결 성공');
})
.catch((err) => {
console.error(err);
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기 중');
});
config/config.json
{
"development": {
"username": "root",
"password": "[root 비밀번호]",
"database": "nodejs",
"host": "127.0.0.1",
"dialect": "mysql"
},
...
}
[nodemon] 2.0.16
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
3001 번 포트에서 대기 중
Executing (default): SELECT 1+1 AS result
데이터베이스 연결 성공
2) 모델 정의
//models/user.js
const Sequelize = require('sequelize');
class User extends Sequelize.Model {
static initiate(sequelize) {
User.init({
name: {
type: Sequelize.STRING(20),
allowNull: false,
unique: true,
},
age: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
},
married: {
type: Sequelize.BOOLEAN,
allowNull: false,
},
comment: {
type: Sequelize.TEXT,
allowNull: true,
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: false,
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) {
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
}
};
module.exports = User;
//models/comment.js
const Sequelize = require('sequelize');
class Comment extends Sequelize.Model {
static initiate(sequelize) {
Comment.init({
comment: {
type: Sequelize.STRING(100),
allowNull: false,
},
created_at: {
type: Sequelize.DATE,
allowNull: true,
defaultValue: Sequelize.NOW,
},
}, {
sequelize,
timestamps: false,
modelName: 'Comment',
tableName: 'comments',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) {
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });
}
};
module.exports = Comment;
| MySQL | VARCHAR | INT | TINYINT | DATETIME | INT + UNSIGNED | INT + UNSIGNED + ZEROFILL |
| 시퀄라이저 | STRING | INTEGER | BOOLEAN | DATE | INTEGER.UNSIGNED | INTEGER.UNSIGNED .ZEROFILL |
| MySQL | NOT NULL | UNIQUE | DEFEALT now() |
| 시퀄라이저 | allowNull : false | unique : true | defaultValue : Sequelize.NOW |
//models/user.js
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
//models/commnet.js
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });
//models/index.js
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');
...
db.sequelize = sequelize;
db.User = User;
db.Comment = Comment;
User.initiate(sequelize);
Comment.initiate(sequelize);
User.associate(db);
Comment.associate(db);
module.exports = db;
3) 관계 정의
//models/user.js
db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
//models/commnet.js
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });




4) 시퀄라이즈 쿼리
(1) Create
INSERT INTO nodejs.users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개1');
const { User } = require('../models');
User.create({
name: 'zero',
age: 24,
married: false,
comment: '자기소개1',
});
(2) Read
SELECT * FROM nodejs.users;
User.findAll({});
SELECT * FROM nodejs.users LIMIT 1;
User.findOne({});
SELECT id, name FROM users ORDER BY age DESC LIMIT 1 OFFSET 1;
User.findAll({
attributes: ['id', 'name'],
order: ['age', 'DESC'],
limit: 1,
offset: 1,
});
SELECT name, married FROM nodejs.users;
User.findAll({
attributes: ['name', 'married'],
});
SELECT name, age FROM nodejs.users WHERE married = 1 AND age > 30;
const { Op } = require('sequelize');
const { User } = require('../models');
User.findAll({
attributes: ['name', 'age'],
where: {
married: true,
age: { [Op.gt]: 30 },
},
});
SELECT id, name FROM users ORDER BY age DESC;
User.findAll({
attributes: ['id', 'name'],
order: [['age', 'DESC']],
});
(3) Update
UPDATE nodejs.users SET comment = '바꿀 내용' WHERE id = 2;
User.update({
comment: '바꿀 내용',
}, {
where: { id: 2 },
});
(4) Delete
DELETE FROM nodejs.users WHERE id = 2;
User.destory({
where: { id: 2 },
});
5) 관계 쿼리
const user = await User.findOne({
include: [{
model: Comment,
}]
});
console.log(user.Comments); // 사용자 댓글
const user = await User.findOne({});
const comments = await user.getComments();
console.log(comments); // 사용자 댓글
5) SQL 쿼리
const [result, metadata] = await sequelize.query('SELECT * from comments');
console.log(result);
1) 모델에서 데이터를 받아 페이지 렌더링
//public/sequelize.js
// 사용자 이름을 눌렀을 때 댓글 로딩
document.querySelectorAll('#user-list tr').forEach((el) => {
el.addEventListener('click', function () {
const id = el.querySelector('td').textContent;
getComment(id);
});
});
// 사용자 로딩
async function getUser() {
try {
const res = await axios.get('/users');
const users = res.data;
console.log(users);
const tbody = document.querySelector('#user-list tbody');
tbody.innerHTML = '';
users.map(function (user) {
const row = document.createElement('tr');
row.addEventListener('click', () => {
getComment(user.id);
});
// 로우 셀 추가
let td = document.createElement('td');
td.textContent = user.id;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.name;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.age;
row.appendChild(td);
td = document.createElement('td');
td.textContent = user.married ? '기혼' : '미혼';
row.appendChild(td);
tbody.appendChild(row);
});
} catch (err) {
console.error(err);
}
}
// 댓글 로딩
async function getComment(id) {
try {
const res = await axios.get(`/users/${id}/comments`);
const comments = res.data;
const tbody = document.querySelector('#comment-list tbody');
tbody.innerHTML = '';
comments.map(function (comment) {
// 로우 셀 추가
const row = document.createElement('tr');
let td = document.createElement('td');
td.textContent = comment.id;
row.appendChild(td);
td = document.createElement('td');
td.textContent = comment.User.name;
row.appendChild(td);
td = document.createElement('td');
td.textContent = comment.comment;
row.appendChild(td);
const edit = document.createElement('button');
edit.textContent = '수정';
edit.addEventListener('click', async () => { // 수정 클릭 시
const newComment = prompt('바꿀 내용을 입력하세요');
if (!newComment) {
return alert('내용을 반드시 입력하셔야 합니다');
}
try {
await axios.patch(`/comments/${comment.id}`, { comment: newComment });
getComment(id);
} catch (err) {
console.error(err);
}
});
const remove = document.createElement('button');
remove.textContent = '삭제';
remove.addEventListener('click', async () => { // 삭제 클릭 시
try {
await axios.delete(`/comments/${comment.id}`);
getComment(id);
} catch (err) {
console.error(err);
}
});
// 버튼 추가
td = document.createElement('td');
td.appendChild(edit);
row.appendChild(td);
td = document.createElement('td');
td.appendChild(remove);
row.appendChild(td);
tbody.appendChild(row);
});
} catch (err) {
console.error(err);
}
}
// 사용자 등록 시
document.getElementById('user-form').addEventListener('submit', async (e) => {
e.preventDefault();
const name = e.target.username.value;
const age = e.target.age.value;
const married = e.target.married.checked;
if (!name) {
return alert('이름을 입력하세요');
}
if (!age) {
return alert('나이를 입력하세요');
}
try {
await axios.post('/users', { name, age, married });
getUser();
} catch (err) {
console.error(err);
}
e.target.username.value = '';
e.target.age.value = '';
e.target.married.checked = false;
});
// 댓글 등록 시
document.getElementById('comment-form').addEventListener('submit', async (e) => {
e.preventDefault();
const id = e.target.userid.value;
const comment = e.target.comment.value;
if (!id) {
return alert('아이디를 입력하세요');
}
if (!comment) {
return alert('댓글을 입력하세요');
}
try {
await axios.post('/comments', { id, comment });
getComment(id);
} catch (err) {
console.error(err);
}
e.target.userid.value = '';
e.target.comment.value = '';
});
// routes/users.js
const express = require('express');
const User = require('../models/user');
const Comment = require('../models/comment');
const router = express.Router();
router.route('/')
.get(async (req, res, next) => {
try {
const users = await User.findAll();
res.json(users);
} catch (err) {
console.error(err);
next(err);
}
})
.post(async (req, res, next) => {
try {
const user = await User.create({
name: req.body.name,
age: req.body.age,
married: req.body.married,
});
console.log(user);
res.status(201).json(user);
} catch (err) {
console.error(err);
next(err);
}
});
router.get('/:id/comments', async (req, res, next) => {
try {
const comments = await Comment.findAll({
include: {
model: User,
where: { id: req.params.id },
},
});
console.log(comments);
res.json(comments);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
// routes/comments.js
const express = require('express');
const { Comment } = require('../models');
const router = express.Router();
router.post('/', async (req, res, next) => {
try {
const comment = await Comment.create({
commenter: req.body.id,
comment: req.body.comment,
});
console.log(comment);
res.status(201).json(comment);
} catch (err) {
console.error(err);
next(err);
}
});
router.route('/:id')
.patch(async (req, res, next) => {
try {
const result = await Comment.update({
comment: req.body.comment,
}, {
where: { id: req.params.id },
});
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
})
.delete(async (req, res, next) => {
try {
const result = await Comment.destroy({ where: { id: req.params.id } });
res.json(result);
} catch (err) {
console.error(err);
next(err);
}
});
module.exports = router;
<빈칸QUIZ>
<코드작성QUIZ>
<빈칸QUIZ 답>
<코드작성QUIZ 답>
1.
INSERT INTO nodejs.users (name, age, married) VALUES ('neo', 30, 0);
2.
User.update({ comment: '수정된 자기소개' }, { where: { id: 1 } });
출처 : 조현영, 『 Node.js 교과서 개정 3판』, 길벗(2022)
Corner Node.js 2
Editor Arom
| [Node.js 2팀] 9장 익스프레스로 SNS 서비스 만들기 (0) | 2025.11.28 |
|---|---|
| [Node.js 2팀] 8장. 몽고디비 (0) | 2025.11.21 |
| [Node.js 2팀] 5장. 패키지 매니저~ 6장. 익스프레스 웹 서버 만들기 (0) | 2025.11.07 |
| [Node.js 2팀] 3장. 노드 기능 알아보기 ~ 4장. http 모듈로 서버 만들기 (0) | 2025.10.31 |
| [Node.js 2팀] 1장. 노드 시작하기 ~ 2장. 알아둬야 할 JavaScript (0) | 2025.10.10 |