MySQL
데이터베이스란
- DBMS : 데이터베이스 관리시스템
- RDBMS : 관계형 DBMS. 대표적으로 Oracle, mysql, mssql 등이 있음.
Datagrip 사용
- Datagrip : 데이터베이스를 위한 IDE. 학생인증을 하면 무료사용가능
- 프로젝트 생성
- alt+insert 혹은 좌측 + 클릭 -> 원하는 데이터베이스 클릭
- 좌측 하단에 download 클릭
- 이후 유저이름, 비밀번호 생성 후 ok
- 좌측 상단 초록 화살표 클릭하여 connect
- 오류
- 내용 : Server returns invalid timezone. Need to set ‘serverTimezone’ property.
- database의 property의 들어가서 advanced 탭을 클릭한 후, serverTimezone 의 값을 Asia/Seoul 로 변경한다.
데이터베이스 및 테이블 생성
- 교재에서는 프롬프트로 진행
데이터 베이스 생성 : CREATE SCHEMA [데이터베이스명]
- 옵션 : DEFAULT CHARACTER SET utf8 -> utf8 셋을 사용하여 한글을 사용할 수 있게함.
- SCHEMA 대신 DATABASE를 사용해도 됨.
- Mysql에선 SCHEMA 와 DATABASE는 같은 말
- 테이블 생성
1
2
3
4
5
6
7
8
9
10
11
12
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 = '사용자 정보'
-> DEFAULT CHARACTER SET = utf8
-> ENGINE = InnoDB;
- CREATE TABLE nodejs.users : 명령어 + 테이블 명. 이때 테이블 명은, 데이터베이스명.테이블명 으로 함.
- use nodejs; 로 이 데이터베이스에 들어왔떈 데이터베이스명 생략가능.
컬럼 선언 : () 안에 선언함. [컬럼명 자료형 옵션] 으로 구성
ex : id INT NOT NULL AUTO_INCREMENT
자료형
- INT / FLOAT / DOUBLE : 숫자
- VARCHAR(자릿수) / CHAR(자릿수) : 문자열 저장
- VARCHAR 은 가변길이로, 20이면 0~20까지 저장가능하지만, CHAR은 반드시 20을 채워야함.
- TEXT : 긴 글을 저장할 때 사용. 수백자 이내면 VARCHAR로 처리하고, 이상이면 TEXT로 처리
- TINYINT : -128 ~ 127 까지의 정수를 저장. 0과 1만 저장하면 BOOLEAN으로 활용 가능.
- DATETIME : 날짜와 시간에 대한 정보를 담고 있음.
- 이 외 많은 자료형들이 있지만 위에가 자주 사용하는 것들.
옵션
- NULL / NOT NULL : 빈칸을 허용할지 안할지.
- AUTO_INCREMENT : 숫자를 자동으로 올림.
- UNSIGNED : 숫자 자료형일때 사용가능. 음수를 무시하고 양수를 더 크게 받을 수 있음.
- ZEROFILL : 숫자의 자릿수가 고정되어있을 때, 앞을 0으로 채움.
- ex) INT(4) 인데 1을 넣으면 0001로 저장.
- DEFAULT : 데이터베이스 저장시 해당 컬럼에 값이 없으면 MySQL이 기본 값을 대신 넣음.
- 위에선 now()를 사용해서, 저장할 당시의 시간을 저장
- now() 대신에 CURRENT_TIMESTAMP 를 사용해도 됨.
- PRIMARY KEY : row를 대표하는 기본키일 경우 설정.
- 컬럼을 다 적고, 위에서처럼 따로 적어도 된다.
- UNIQUE INDEX : 값이 고유해야하는지 묻는 옵션. PRIMARY KEY는 자동으로 설정됨.
- CONSTRAINT [제약조건명] FOREIGN KEY [컬럼] REFERENCES [참고하는 테이블명] [참고하는 컬럼명]
- 외래키. 서로 연결하는 것.
- ON UPDATE / DELETE : 연결한 것이 수정되거나 삭제될 시 하는 행위 정의
- CASCADE로 하면 같이 수정하거나 삭제함.
테이블 자체 옵션
- 테이블 컬럼 작성이 끝나고 이후에 옵션으로 붙임.
- COMMENT : 테이블에 대한 보출 설명
- DEFAULT CHARACTER SET : utf8으로 설정하지 않으면 한글입력이 안됨.
- ENGNED : MylSAM과 InnoDB를 제일 많이 사용함.
- 테이블 확인 : desc [테이블명]
- 테이블 제거 : drop table [테이블명]
CRUD 작업하기
Create : 그냥 데이터를 넣는 것.
- insert into [테이블명] (컬럼, 컬럼) VALUES (값, 값);
read : SELECT (컬럼, 컬럼) FROM [테이블명]
- 모든 컬럼을 조회하려면 * 사용
- WHERE 로 특정 조건을 가진 데이터만 조회가능
- EX) WHERE married = 1 AND age > 30;
ORDER BY [컬럼명] [ASC DESC] - 정렬 기능.
- LIMIT [숫자]
- 조회할 로우 개수 설정.
- OFFSET [건널뛸 숫자]
- 처음부터 몇개까지 건널 뛰고 출력할 건지 정할 수 있음.
- 반드시 LIMIT 과 함께 쓰여야함.
Update : UPDATE [테이블명] SET [컬럼명=바꿀값] WHRER [조건]
- 조건에 맞는 row의 해당하는 column을 수정할 수 있음.
Delete : DELETE FROM [테이블명] WHERE [조건]
- 조건에 맞는 row를 삭제
시퀄라이즈 사용
- ORM : 자바스크립트 객체와 데티어베이스의 관계를 매핑해주는 도구.
- MySQL외 다른 MariaDB, PostgreSQL, SQLite, MSSQL 등 다른 데이터베이스도 같이 쓸 수 있음.
- 자바스크립트 구문을 알아서 SQL로 바꿔줌. 따라서 SQL 언어를 직접 사용하지 않아도 자바스크립트 만으로 MySQL을 조작할 수 있고, 다룰 수 있음.
설치 후 초기화
설치 : sequelize, sequelize-cli, mysql2
- sequelize :
- sequelize-cli : 시퀄라이즈 명령어를 실행하기 위한 패키지
- mysql2 : mysql과 시퀄라이즈를 이어주는 드라이버
설치 후 sequelize init 명령어로 초기화 -> config, models, migrations, seeders 폴더 생성
- models/index.js에서 sequelize cli 가 자동으로 생성해주는 코드는 필요없는 부분이 많음. 따라서 다음처럼 정리 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Sequelize = require("sequelize");
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;
module.exports = db;
MySQL 연결
- 시퀄라이즈 연결
1
2
3
4
5
6
7
8
9
10
11
const { sequelize } = require("./models");
...
sequelize
.sync({ force: false }) // 서버 실행 시 mysql 연결. force:true 일 경우, 서버 실행 시 마다 테이블을 재생성함. 테이블을 잘못만든 경우 true로 설정
.then(() => {
console.log("데이터베이스 연결 성공");
})
.catch((err) => {
console.error(err);
});
- MySQL과 연동할 땐, config 폴더 안의 config.json 정보가 사용됨.
- operatorAliases가 있다면 삭제.
- 나머지는 적절히 수정
모델 정의하기
- 시퀄라이즈 모델 == MySQL 테이블
- 시퀄라이즈는 모델과 MySQL 테이블을 연결해주는 역할을 함.
- 보통 모델 이름은 단수형으로, 테이블이름은 복수형으로 함.
모델 함수
- static init
- 테이블에 대한 설정을 함.
- static associate
- 다른 모델과의 관계를 적음.
- static init
- 자료형 대응
MySQL | 시퀄라이즈 |
---|---|
VARCHAR(100) | STRING(100) |
INT | INTEGER |
TINYINT | BOOLEAN |
DATETIME | DATE |
INT UNSIGNED | INTEGER.UNSIGNED |
NOT NULL | allowNull: false |
UNIQUE | unique: true |
DEFAULT now() | defaultValue: Sequelize.NOW |
- 자세한 모델 정의/연결법은 강의에서 찾아보기 [https://thebook.io/080229/ch07/06/02-04/]
관계정의하기
- 1:N - 시퀄라이즈에선 hasMany 라는 메서드로 표현됨.
- belongsTo : 로우를 불러올대 연결된 테이브르이 로우를 가져오도록 함.
- 어디에 belongsTo를 쓰는가 -> 다른 모델의 정보가 들어가는 테이블에 쓰면 됨.
- hasMany에서는 sourceKey를 쓰고, belongsTo에서는 targetKey를 사용
- 1:1 - hasOne 사용
- N:M - belongsToMany
- 양쪽에서 belongsToMany로 연결해주면 됨.
- through 속성에 넣은 이름으로 새로운 모델을 만들어냄.
쿼리 알아보기
- 쿼리는 프로미스를 반환하므로 then을 붙여서 결괏값을 받을 수 있다.
대응
- 주의점 : MySQL의 자료형이 아니라, 시퀄라이즈 모델에서 정의한 자료형대로 넣어야함. 시퀄라이즈가 자동으로 변경함.
- 조회
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
SELECT * FROM nodejs.users;
User.findAll({});
SELECT * FROM nodejs.users LIMIT 1;
User.findOne({});
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: 1,
age: { [Op.gt]: 30 }, // 시퀄라이즈는 자바스크립트 객체를 사용하여 쿼리를 생성하므로, 특수 연산자 사용. Op.gt 은 operator greater than 임.
},
});
//Op.or 사용
SELECT id, name FROM users WHERE married = 0 OR age > 30;
const { Op } = require('sequelize');
const { User } = require('../models');
User.findAll({
attributes: ['id', 'name'],
where: {
[Op.or]: [{ married: 0 }, { age: { [Op.gt]: 30 } }],
},
});
//Order by
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;
User.findAll({
attributes: ['id', 'name'],
order: [['age', 'DESC']],
limit: 1,
});
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,
});
- 수정 : 첫번째로 수정할 내용, 두번째로 조건
1
2
3
4
5
6
UPDATE nodejs.users SET comment = '바꿀 내용' WHERE id = 2;
User.update({
comment: '바꿀 내용',
}, {
where: { id: 2 },
});
- 생성
1
2
3
4
5
6
7
8
9
10
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',
});
- 삭제
1
2
3
4
DELETE FROM nodejs.users WHERE id = 2;
User.destory({
where: { id: 2 },
});
관계쿼리
- 관계쿼리 : find 메소드에서 옵션으로 include를 주면, JOIN 메소드 사용가능.
1
2
3
4
5
6
7
8
// 특정사용자를 가져오면서, 댓글까지 모두 가져오고 싶을때
const user = await User.findOne({
include: [
{
model: Comment,
},
],
});
- 여기서 user.Comments로 접근 가능.
- 관계를 설정했다면, 아래 메소드 지원
- getComments, setComments, addComment, addComments, removeComments
- 이렇게, 동사뒤에 모델의 이름을 붙여서 사용한다.
- 동사 뒤에 모델 이름을 바꾸고 싶으면, 관계 설정시 as 옵션을 사용할 수 있음.
1
2
3
4
5
db.User.hasMany(db.Comment, {
foreignKey: "commenter",
sourceKey: "id",
as: "Answers",
});
- include 나 관계 쿼리 메소드에도 where나 attributes 같은 옵션을 사용할 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const user = await User.findOne({
include: [
{
model: Comment,
where: {
id: 1,
},
attributes: ["id"],
},
],
});
// 또는
const comments = await user.getComments({
where: {
id: 1,
},
attributes: ["id"],
});
- 관계쿼리 수정, 생성, 삭제 때는 조금 다르게 함.
1
2
3
4
const user = await User.findOne({});
const comment1 = await Comment.create();
const comment2 = await Comment.create();
await user.addComment([comment1, comment2]);
SQL 쿼리하기
- 직접 SQL 쿼리를 사용할 수 있음.
1
2
const [result, metadata] = await sequelize.query("SELECT * from comments");
console.log(result);