상세 컨텐츠

본문 제목

[Node.js 1팀] 7장. MySQL

25-26/Node.js 1

by a-rom 2025. 11. 14. 10:00

본문

728x90


7장. MySQL

 

7-1. 데이터 베이스란?

: 관련성을 가지며 중복이 없는 데이터들의 집합

 

- 데이터베이스를 관리하는 시스템을 DBMS(DataBase Management System)라고 한다.

  > DBMS 중에는 RDBMS(Relational DBMS)라고 부르는 관계형 DBMS가 많이 사용된다

    * 대표적인 RDBMS로 Oracle, MySQL, MSSQL 등이 있음

    * 이들은 SQL이라는 언어를 사용해 데이터를 관리함

- 보통 서버의 하드 디스크나 SSD 등의 저장 매체에 데이터를 저장한다.

  > 저장 매체가 고장 나거나 사용자가 직접 데이터를 지우지 않는 이상 계속 데이터가 보존된다.

    * 서버 종료 여부와 상관없이 데이터를 계속 사용할 수 있음

  > 서버에 데이터베이스를 올리면 여러 사람이 동시에 사용할 수 있다.

    * 사람들에게 각각 다른 권한을 줘서 어떤 사람은 읽기만 가능하고, 어떤 사람은 모든 작업을 가능하게 할 수 있음

 

 

7-4. 데이터베이스 및 테이블 생성하기

1) MySQL 프롬프트에 접속

$ mysql -h localhost -u root -p
Enter password: [비밀번호 입력]
mysql>

  - 경로에 상관없이 콘솔에 mysql -h localhost -u root -p 명령어를 입력하면 됨

 

2) 데이터 베이스 생성

mysql> CREATE SCHEMA `nodejs` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
Query OK, 1row affected (0,01sec)
mysql> use nodejs;
Database changed

  - CREATE SCHEMA [데이터베이스명] : 데이터베이스를 생성하는 명령어

     > MySQL에서 데이터베이스와 SCHEMA(스키마)는 같은 개념

  - use nodejs :  앞으로 nodejs라는 데이터베이스를 사용하겠다고 선언

  - DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci : 한글과 이모티콘 사용 가능하게

    > utf8mb4 여야 데이터베이스에서 한글과 이모티콘 사용 가능

  - SQL 구문을 입력할 때는 마지막에 세미콜론(;)을 붙여야 해당 구문이 실행됨

     > 세미콜론을 붙이지 않을 경우, 프롬프트가 다음 줄로 넘어가서 다른 입력이 들어오기를 계속 기다림

  - CREATE SCHEMA 와 같이 mySQL이 기본적으로 알고 있는 구문을 예약어라고 함

     > 예약어는 소문자로 써도 되지만, 가급적 대문자로 쓰는 것이 좋음

        

3) 테이블 생성하기

mysql> CREATE TABLE nodejs.users (
    -> id INT NOT NULL AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL,
    -> age INT USIGNED 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)

  -   테이블이란? :  데이터가 들어갈 수 있는 틀

  - CREATE TABLE [데이터베이스명.테이블명] : 테이블을 생성하는 명령어

    > 예제에서는 nodejs 데이터베이스 내에 users 테이블을 생성함

    > 이전에 use nodejs; 명령어를 실행했으므로 CREATE TABLE users처럼 데이터베이스명 생략 가능

  - id(고유 식별자), name(이름), age(나이) 등... 데이터를 넣을 때 컬럼 규칙에 맞는 정보들만 넣을 수 있음

    > 생년월일이나 몸무게 같이 컬럼으로 만들어두지 않은 정보들은 저장 불가능

 

  ``컬럼의 자료형``

  - INT(정수)

    > 소수까지 저장하고 싶으면 FLOAT나 DOUBLE 자료형 사용

  - VARCHAR(자릿수)

    > CHAR(자릿수) 둘은 비슷해 보이지만, VARCHAR은 가변 길이이고, CHAR은 고정 길이이다

    > CHAR에 주어진 길이보다 짧은 문자열을 넣으면 부족한 자릿수만큼 스페이스가 채워짐

  - TEXT(긴 글)

    > VARCHAR은 수백 자 이내의 문자열 , 그보다 길면 TEXT 사용

  - TINYINT(정수)

    > -128 ~ 127까지의 정수를 저장할 때 사용

    > 1 또는 0만 저장한다면 불값(Bool)과 같은 역할을 할 수 있음

  - DATETIME (날짜와 시간)

    > 날짜만 담는 DATE와 시간만 담는 TIME으로 따로 사용 가능

 

  ``그 외 옵션``

  - NULL / NOT NULL : 빈칸을 허용할지에 대한 여부를 묻는 옵션

    > NOT NULL의 경우, 반드시 데이터를 입력해야 함

  - AUTO_INCREMENT : 숫자를 저절로 올리겠다는 뜻

    > 처음 A라는 사람이 데이터를 넣으면 MySQL은 알아서 id로 1번을 부여하고,

       다음에 B라는 사람이 데이터를 넣으면 자동으로 id 2번을 부여

  - UNSIGNED : 숫자 자료형에 적용되는 옵션으로, 음수 범위 지정 못 하게 함

  - ZEROFILL : 숫자의 자릿수가 고정되어 있을 때 사용 가능하며, 빈 자리에 0을 채움

  - created_at : 데이터베이스 저장 시, 해당 컬럼에 값이 없을 때 MySQL이 기본값을 대신 넣음

    > 예제에서 now()는 현재 시각을 넣으라는 뜻으로, 사용자 정보를 넣으면 created_at 컬럼에 자동으로 시각 기록됨

  - PRIMARY KEY : 해당 컬럼이 기본 키인 경우 사용

    > 기본 키란 로우를 대표하는 고유한 값을 의미

    > 데이터베이스에 데이터를 넣을 때 로우 단위로 넣는데, 이때 로우들을 구별할 고유한 식별자 필요함

    > 이름, 나이, 결혼 여부 등은 다른 사람과 겹칠 수 있으므로, 따로 id라는 컬럼을 이용해 고유한 번호 부여

  - UNIQUE INDEX : 해당 값이 고유해야 하는지에 대한 옵션

    > PRIMARY KEY 와 UNIQUE INDEX는 데이터베이스가 별도로 컬럼을 관리해 조회 시 속도가 빨라짐

    > PRIMARY KEY는 자동으로 UNIQUE INDEX를 포함

  - ASC (오름차순) <-> DESC (내림차순)

 

  ``테이블 자체에 대한 설정``

  - COMMENT : 테이블에 대한 보충 설명 

    > 이 테이블이 무슨 역할을 하는 지 등을 적어둠 

    > 필수 요소 아님

  - ENGINE : 테이블 엔진 설정

    > MyISAM과 InnoDB가 가장 많이 쓰임

 

  4) 테이블 확인 및 제거 방법

mysql> DESC users;  -- DESC [테이블명] : 만들어진 테이블 확인

mysql> DROP TABLE users;  --DROP TABLE [테이블명] : 테이블 제거

 

 

7-5. CRUD 작업하기

: CRUD (Create, Read, Update, Delete) 

  - 데이터베이스에서 많이 사용하는 네 가지 작업을 일컫음

 

1) Create (생성)

  - 데이터를 생성해 데이터베이스에 넣는 작업

mysql> INSERT INTO nodejs.users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개1');
Query OK, 1row affected (0.01 sec)

  - 이전에 use nodejs; 명령어를 사용했다면 테이블명으로 nodejs.users 대신 users만 사용해도 됨

  - INSERT INTO [테이블명] ([컬럼1], [컬럼2], ...) VALUES ([값1], [값2], ...) : 데이터를 넣는 명령어

    * 예제의 경우, name에 zero, age에 24 ,,, 가 들어감

    * id는 AUTO_INCREMENT에 의해, created_at 은 DEFAULT 값에 의해 자동으로 들어감

 

2) READ (조회)

  - 데이터베이스에 있는 데이터 조회

mysql> SELECT * FROM nodejs.users;
-- 테이블 조회 결과 나옴
rows in set (0.00 sec)

  - SELECT * FROM [테이블명] : users 테이블의 모든 데이터 조회

mysql> SELECT name, married FROM nodejs.users;
-- 테이블 조회 결과 나옴
rows in set (0.00 sec)

  - SELECT 다음에 조회를 원하는 컬럼을 넣으면 특정 컬럼만 조회할 수 있음

mysql> SELECT name, married FROM nodejs.users WHERE married = 1 AND age > 30;
-- 테이블 조회 결과 나옴
rows in set (0.00 sec)

  - WHERE 절을 사용하면 특정 조건을 가진 데이터만 조회할 수 있음

    > MySQL에서는 undefined라는 자료형을 지원하지 않으므로 WHERE 옵션에 undefined가 들어가면 안 된다.

  - AND로 여러 조건을 묶을 수 있음

    > AND는 조건들을 모두 만족, OR은 조건들 중 어느 하나라도 만족하는 데이터 찾음

mysql> SELECT id, name FROM nodejs.users ORDER BY age DESC LITMIT 1 OFFSET 1;
-- 테이블 조회 결과 나옴
rows in set (0.00 sec)

  - ORDER BY [컬럼명] [ASC/DESC] : 오름차순/내림차순 정렬

  - LIMIT [숫자] : 조회할 로우 개수 설정

  - OFFSET [건너뛸 숫자] : 처음 n개를 건너뛰고 조회하게 설정

 

3) Update (수정)

  - 데이터베이스에 있는 데이터 수정

mysql> UPDATE nodejs.users SET comment = '바꿀 내용' WHERE id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warning: 0

  - UPDATE [테이블명] SET [컬럼명=바꿀 값] WHERE [조건] : 수정 명령어

    > AND나 OR을 사용해 조건 여러 개 제시 가능

 

4) Delete (삭제)

  - 데이터베이스에 있는 데이터를 삭제

mysql> DELETE FROM nodejs.users WHERE id=2;
Query OK, 1 row affected (0.00sec)

  - DELETE FROM [테이블명] WHERE [조건] : 삭제 명령어  

    > AND나 OR을 사용해 조건 여러 개 제시 가능

 

 

7-6. 시라이즈 사용하기

: 시퀄라이즈는 MySQL 작업을 쉽게 할 수 있도록 도와주는 라이브러리

: 자바스크립트 구문을 알아서 SQL로 바꿔줌

npm i express morgan nunjucks sequelize-cli mysql2
npm i -D nodemon

- 위는 시퀄라이즈에 필요한 패키지 설치 명령어

- sequelize-cli : 시퀄라이즈 명령어를 실행하기 위한 패키지

- mysql2 : MySQL과 시퀄라이즈를 이어주는 드라이버

 

1) MySQL 연결하기

// app.js 생성하여 익스프레스와 시퀄라이즈 연결 코드 작성
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const nunjucks = require('nunjucks');

const { sequelize } = require('./models'); 
// = require('./models/index.js');와 같음
// 폴더 내의 index.js 파일은 require할 때 이름을 생략할 수 있음
const indexRouter = require('./routes');
const usersRouter = require('./routes/users');
const commentsRouter = require('./routes/comments');

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 })  
// db.sequelize를 불러와 sync 메서드를 사용하여 서버를 실행할 때 MySQL과 연동되도록 함
// force: false를 true로 설정하면 서버를 실행할 때마다 테이블을 재생성함
// 테이블을 잘못 만든 경우 true로 설정하면 됨
  .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('/', indexRouter);
app.use('/users', usersRouter);
app.use('/comments', commentsRouter);

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.json 코드 수정
{
  "development": {
    "username": "root",
    "password": {비밀번호}, //mysql 비밀번호
    "database": "nodejs", //데이터베이스명으로 바꾸기
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  ...
 }

 

2) 모델 정의하기

// models/user.js
const Sequelize = require('sequelize');

class User extends Sequelize.Model {
  static initiate(sequelize) {
    User.init({
      name: {
        type: Sequelize.STRING(20),  // STRING = VARCHAR
        allowNull: false,  // = NOT NULL
        unique: true,  // = UNIQUE
      },
      age: {
        type: Sequelize.INTEGER.UNSIGNED,  // INTEGER = INT
        allowNull: false,
      },
      married: {
        type: Sequelize.BOOLEAN,  // BOOLEAN = TINYINT
        allowNull: false,
      },
      comment: {
        type: Sequelize.TEXT,
        allowNull: true,
      },
      created_at: {
        type: Sequelize.DATE,  // DATE = DATETIME
        allowNull: false,
        defaultValue: Sequelize.NOW,  // = DEFAULT now()
      },
    }, {
      sequelize,
      // db.sequelize 객체를 넣어야 함
      // static initiate 메서드의 매개변수와 연결
      timestamps: false,
      // true면 시퀄라이즈가 createaAt, updateAt 컬럼 추가, 수정될 때 시간 입력
      underscored: false,
      modelName: 'User',
      tableName: 'users',
      paranoid: false,
      // true면 deletedAt컬럼 추가, 로우 삭제할 때 시간 입력
      charset: 'utf8',
      collate: 'utf8_general_ci',
    });
  }

  static associate(db) {
    db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
  }
};

module.exports = User;
// 생성한 모델을 index.js와 연결
const Sequelize = require('sequelize');
const User = require('./user');
const Comment = require('./comment');

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {};

const sequelize = new Sequelize(config.database, config.username, config.password, config);

db.sequelize = sequelize;

db.User = User;
db.Comment = Comment;

User.initiate(sequelize);	//각각의 모델의 static initiate 메서드를 호출하는 것
Comment.initiate(sequelize);

User.associate(db);
Comment.associate(db);

module.exports = db;

 

3) 관계 정의하기

// user.js
static associate(db) {
	db.User.hasMany(db.Comment, { foreignKey: "commenter", sourceKey: "id" });
}

// comment.js
static associate(db) {
	db.Comment.belongsTo(db.User, { FOREIGNKEYS: "commenter", targetKey: "id" });
}

  - db.User.hasOne(db.Info, { foreignKey: 'UserId', sourceKey: 'id' }); 

  - 1:1 대응일 때 = hasOne, belongsTo 메서드 사용

  - 1:N 대응일 때 = hasMany, belongsTo 메서드 사용

  - N:M 대응일 때 = belongsToMany 메서드 사용

 

4) 관계 쿼리

: MySQL로 보면 JOIN 기능

// User 모델이 Comment 모델과 hasMany-belongsTo 관계가 맺어 있을 때...
const user = await User.findOne({
  include: [{
    model: Comment,
  ]}
});
console.log(user.Comments);  // 사용자 댓글

  - 특정 사용자를 가져오면서, 그 사람의 댓글까지 모두 가져오고 싶다면 include 속성 사용

  - 어떤 모델과 관계가 있는지를 include 배열에 넣어주면 됨 

  - 댓글이 여러 개일 수 있으므로 user.Comments로 접근 가능 

// 관계를 설정했다면...
const user = await User.findOne({});
const comments = await user.getComments();
console.log(user.Comments);  // 사용자 댓글

  - getComments(조회)

  - setComments(수정)

  - removeComments(삭제)

  - addComment(하나 생성)

  - addComments(여러 개 생성)

const user = await User.findOne({});
const comment1 = await Comment.create();
const comment2 = await Comment.create();
await user.addComment([comment1, comment2]);  // 배열 사용

 

  - 여러 개를 추가할 때는 배열로 추가 가능

    > 수정과 삭제도 마찬가지


 

QUIZ

 

1. 데이터베이스를 관리하는 시스템을 (   )라고 한다.
2. DBMS는 (   )이라는 언어를 사용한다
3. SQL 구문을 입력할 때는 마지막에 (   )을 붙여야 해당 구문이 실행됨
4. CRUD는 각각 (  ,  ,  ,  )  
5. (   )는 MySQL 작업을 쉽게 할 수 있도록 도와주는 라이브러리

 

6. 데이터 베이스를 생성하는 명령어 코드를 작성하시오. (데이터베이스명은 nodejs)
7.  테이블을 생성하는 명령어 코드를 작성하시오. (데이터베이스명은 nodejs, 테이블명은 users)

 

 

정답

1. 데이터베이스를 관리하는 시스템을 DBMS라고 한다.
2. DBMS는 SQL이라는 언어를 사용한다
3. SQL 구문을 입력할 때는 마지막에 세미콜론(;)을 붙여야 해당 구문이 실행됨
4. CRUD (Create, Read, Update, Delete) 
5. 시퀄라이즈는 MySQL 작업을 쉽게 할 수 있도록 도와주는 라이브러리

6. CREATE SCHEMA nodejs
7. CREATE TABLE nodejs.users

 

 

 

출처 : 조현영,  Node.js 교과서 개정 3판, 길벗(2022),

 

Corner Node.js 1
Editor : RACCOON

728x90

관련글 더보기