> For the complete documentation index, see [llms.txt](https://ssosso.gitbook.io/study/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ssosso.gitbook.io/study/javascript/node.js/7.-mysql.md).

# 7. MySQL

## 7. MySQL

### 7.1 데이터베이스란?

데이터를 저장 및 조작 할 수 있는 시스템 -> DBMS

* RDBMS : MySQL
* NoSQL : MongoDB

### 7.2 MySQL 설치하기

도커로 대체

```bash
# 도커설치
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce

# docker image 생성 및 실행
$ docker run -it -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 --name mysql5.7 mysql:5.7
```

### 7.3 DB SQL 설치

워크벤치 대신 Datagrip이나 DBeaver(무료) 추천\
워크벤치 생략

* Datagrip : <https://www.jetbrains.com/datagrip/>
* DBeaver : <https://dbeaver.io/>

### 7.4 데이터베이스 및 테이블 생성하기

```sql
-- Database 생성
CREATE DATABASE nodejs;

-- Database 사용
use nodejs;

-- 테이블 설명
DESC users;

DROP TABLE 테이블명;
...
```

자료형

* INT : 정수의미. 소수까지 저장 -> FLOAT, DOUBLE 사용&#x20;
* VARCHAR : 가변길이. 몇백자 이내
* TINYINT : -127 \~ 128
* TEXT : 긴글 저장
* DATETIME : 날짜 및 시간에대 한 정보. 날짜만 -> DATE, 시간 -> TIME

### 7.5 CRUD 작업하기 (생성, 읽기, 수정, 삭제)

* C : Create. 생성
  * insert into table values (값,...)
* R : Read. 읽기
  * select \* from table
* U : Update. 수정
  * update table set field1 = x, field2 = y ..
* D : Delete. 삭제
  * delete from table where \~

### 7.6 시퀄라이즈 사용하기

* ORM : 객체와 데이터베이스의 릴레이션 매핑
* 자바스크립트 구문 -> SQL로 바꿔줌
* 모듈 설치

  ```bash
  # project 생성
  $ express learn-sequelize --view=pug

  # sequelize와 mysql2 패키지 설치, cli 전역설치
  $ npm i sequelize mysql2
  $ npm i -g sequelize-cli
  $ sequelize init
  ```
* config.json 내용
  * operatorsAliases : 보안에 취약한 연산자를 사용할지 여부 (false입력 : 사용안함)
  * 4대 정보 : username, password, database, host 정보 알맞게 입력&#x20;

    ```javascript
    {
    "development": {
      "username": "root",
      "password": null,
      "database": "database_development",
      "host": "127.0.0.1",
      "dialect": "mysql",
      "operatorsAliases": false
    },
    "test": {
      "username": "root",
      "password": null,
      "database": "database_test",
      "host": "127.0.0.1",
      "dialect": "mysql",
      "operatorsAliases": false
    },
    "production": {
      "username": "root",
      "password": null,
      "database": "database_production",
      "host": "127.0.0.1",
      "dialect": "mysql",
      "operatorsAliases": false
    }
    }
    ```

```javascript
var sequelize = require('./models/index').sequelize;
var app = express();
sequelize.sync(); // 메서드 없는데;;?
```

* models/user.js

  user 정보&#x20;

  sequlize.define 메서드로 모델 정의. 시퀄라이즈와 MySQL 자료형은 약간 상이

| MySQL    | 시퀄라이즈   |
| -------- | ------- |
| VARCHAR  | STRING  |
| INT      | INTEGER |
| TINYINT  | BOOLEAN |
| DATETIME | DATE    |
| 테이블명 복수형 | 모델명 단수형 |

```javascript
// define(모델명, 스키마정의, 테이블옵션)
// user.js
module.exports = (sequelize, DataTypes) => {
  return sequelize.define('user', {
    name: {
      type: DataTypes.STRING(20),
      allowNull: false, // -> not null 옵션과 동일
      unique: true      // -> unique 옵션과 동일
    },
    age : {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull : false
    },
    married:{
      type: DataTypes.BOOLEAN,
      allowNull: true
    },
    comment :{
      type: DataTypes.TEXT,
      allowNull:false
    },
    created_at :{
      type: DataTypes.DATE,
      allowNull : false,
      defaultValue: sequelize.literal('now()')  // -> default 옵션과 동일
    },
  }, {
    timestamps: false // true : createdAt, updatedAt 컬럼 자동 추가 및 자동 업데이트
  });
};

// comment.js
module.exports = (sequlize, DataTypes) => {
  return sequlize.define('comment', {
    comment: {
      type: DataTypes.STRING(100),
      allowNull: false
    },
    created_at: {
      type: DataTypes.DATE,
      allowNull: true,
      defaultValue: sequlize.literal('now()')
    }
  }, {
    timestamps: false
  });
};

// index.js
// db 객체의 property와 js의 객체 정보 연결
db.User = require('./user')(sequelize, Sequelize);
db.Comment = require('./comment')(sequelize, Sequelize);
```

* 위 외에 테이블옵션
  * paranoid : timestamps가 true인 경우만 사용 가능, deletedAt 컬럼이 추가됨. **삭제시 삭제된 날짜가 입력됨** (삭제하진 않고 데이터를 남겨두는 이유는 백업 및 히스토리 관리 때문)
  * underscored : createdAt, updatedAt, deleteAt 컬럼과 시퀄라이즈가 자동으로 생성해주는 관계 컬럼들의 이름을 스네이크케이스 형식으로 변경 해줌. 스네이크케이스란 대문자 대신 \_를 사용하는 방식. ex : createdAt -> created\_at
  * tableName : 테이블 이름을 다른것으로 설정하고 싶을 때 사용. 시퀄라이즈는 자동으로 첫번째 인자(모델값)값을 복수형으로 만들어 테이블 이름으로 사용함. user -> users, comment -> comments
* 1:N 관계 표현 hasMany메서드 사용. foreignKey 속성으로 값 일치. sourceKey 키값(id), targetKey 키값(id)

  ```javascript
  // user는 comment를 많이 갖을 수 있다
  db.User.hasMany(db.Comment, {foreignKey: 'commenter', sourceKey: 'id'});
  // commnet는 user에 속할 수 있다
  db.Comment.belongsTo(db.User, {foreignKey: 'commenter', targetKey: 'id'});
  ```
* 1:1 관계 표현 hasOne 메서드 사용. foreignKey 속성으로 값 일치. sourceKey 키값(id), targetKey 키값(id)

  ```javascript
  // user는 info를 하나 갖고 있다.
  db.User.hasOne(db.Info, {foreignKey: 'user_id', sourceKey: 'id'});
  // info는 user에 속할 수 있다.
  db.Info.belongsTo(db.User, {foreignKey: 'user_id', targetKey: 'id'});
  ```
* N:M 관계 표현 (다대다) belongsToMany 메서드 사용. through 속성은 중간 관계 테이블 이름 이라고 보면될듯.

  ```javascript
  // post(게시글)은 여러개의 해시태그를 갖을 수 있다.
  db.Post.belongsToMany(db.Hashtag, {through: 'PostHashtag'});
  // hashtag(해시태그)는 여러개의 게시글에 달릴 수 있다.
  db.Hashtag.belongsToMany(db.Post, {through: 'PostHashtag'});
  ```
* get+모델이름 복수형

  ```javascript
  async (req, res, next) => {
  const tag = await Hashtag.find({where:{title:'node'}});
  const posts = await tag.getPosts();
  }
  ```

### 시퀄라이즈 쿼리 알아보기

시퀄라이즈만의 방식\
반환 : 프로미스\
async/await 같이 사용 가능

* order : 정렬방식
* attributes : select 컬럼 명시
* 시퀄라이즈의 OP -> 오퍼레이터

```javascript
// INSERT INTO users (name, age, married, comment) VALUES('zero', 24, 0, '자기소개1');
const {User} = require('../models')
User.create({
  name: 'zero',
  age: 24,
  married: false,
  comment: '자기소개1'
});

// select * from users;
User.findAll({});

// select * from users limit 1;
Uesr.find({});

// select name, married from users;
User.findAll({
  attributes:['name', 'married']
});

// select name, age from users where married = 1 and age > 30
const {User, Sequelize :{Op}} = require('../models');
User.findAll({
  attributes:['name', 'age'],
  where: {
    married:1,
    age: {[Op.gt]:30}
  }
})

// select id, name from users order by age desc;
User.findAll({
  attributes:['id', 'name'],
  order: [[]]
})

// select id, name from users where married = 0 OR age >30;
const {User, Sequelize: {Op}} = require('../models');
User.findAll({
  attributes: ['id', 'name'],
  where: {
    [Op.or]: [{married: 0}, {age: {[Op.gt]:30}}]
  }
})

// select id, name from users order by age desc;
User.findAll({
  attributes: ['id', 'name'],
  order: [['age', 'DESC']]
})

// 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
})

// update users set comment = '내용' where id = 2;
User.update({
  comment: '내용' // 수정내용
},{
  where: {id: 2}  // 수정대상 로우 찾기
})

// delete from users where id = 2
User.destroy({
  where:{id: 2}
})
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ssosso.gitbook.io/study/javascript/node.js/7.-mysql.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
