[ON SOPT] Server 4th Seminar
4주차 세미나 사전준비
- RDS 세팅
- MySQL workbench 설치
Database
데이터베이스
서버는 데이터베이스에 접근하여 데이터들을 Read/Write 한다.
데이터베이스
- 관련성을 가지며 중복이 없는 데이터의 집합
- 데이터베이스를 관리하는 시스템을 DBMS(Database Management System) 이라 함.
- Relational Database(관계형 데이터 베이스): key-value 관계를 테이블화 한 것
데이터 베이스 용어 정리
Primary Key(기본키) : 다른 데이터와 구별할 수 있는 식별자
- 한 테이블에는 하나 혹은 그 이상의 primary key가 있어야 함
- Not Null, Unique
Index : 데이터 색인 기능
- 관계형 데이터 베이스에서 검색 속도를 높이기 위한 도구
- Unique, 특정 데이터 대표
- 주로 기본키로 사용됨
Foreign key(외래키) : 한 테이블의 column 중 다른 테이블의 row를 식별할 수 있는 key
Relation 관계
1 : 1 관계
말 그대로 1:1로 매핑되는 관계 (예: 이름 - 주민번호)
1 : N 관계
한쪽 개체가 관계를 맞은 개체 쪽의 여러 개체를 가질 수 있는 관계 (예: 이름 - 이메일)
테이블 한 개로 담기에는 중복되는 정보가 너무 많아, 테이블을 나누어 준다.
M : N 관계
양쪽 개체가 서로 1:N 관계로 보고 있는 관계 (예: 이름 - 스터디)
이러한 경우에는 테이블을 잘 나누어 주어야 한다 → 정규화
정규화
관계형 데이터 베이스를 논리적이고 직관적으로 만드는 과정
목적
- 불필요한 데이터 제거
- 논리적인 데이터 저장
- 이상현상 방지
- 삽입 이상 : 새 데이터를 삽입할 때 불필요한 데이터도 함께 넣어줘야 되는 문제
- 갱신 이상 : 중복 튜플인데 일부만 변경되는 문제 (데이터 모순)
- 삭제 이상 : 튜플을 삭제했는데 중요 데이터가지 함께 삭제되는 데이터 손실 문제
< 1차 정규화 >
조건: 각 row 마다 column이 값을 하나씩만 가져야 함 (즉, 컬럼이 원자값을 가져야 함)
쉬운 설명:
- 모든 Domain에 값이 한 개씩만
- 반복되는 group이 없음
- 기본키(PK)로 각 데이터가 식별 가능해야함
< 2차 정규화 >
조건: 부분 함수적 종속이 없이, 모든 컬럼이 완전 함수적 종속을 만족함
함수적 종속: X에 의해 Y가 결정되면, Y는 X에 대해 함수적 종속이다
이 때 X를 결정자, Y를 종속자라고 한다
부분 함수적 종속: {X1, X2} → Y 에서, X2 만으로도 Y가 결정되는 경우
완전 함수적 종속: {X1, X2} → Y 에서, X1과 X2가 모두 있어야 Y가 결정되는 경우
< 3차 정규화 >
조건: 2차 정규화가 되어 있고, 이행적 함수 종속이 없어야 함
쉬운 설명: 기본 키가 아닌 속성들은 기본 키에만 의존해야 함
< 역 정규화 >
시스템의 퍼포먼스를 위해 정규화에 위배되는 행위를 하는 것
Sequelize ORM (Object Relational Mapping)
Sequelize ORM이란?
NodeJS에서 JS의 객체와 DB의 관계를 매핑해주는 라이브러리!
SQL을 사용하지 않고 JS로 DB에 접근한다
Sequelize Project
처음: npm install sequelize-cli sequelize mysql2
로 모듈 3개 깔아주고, sequelize init
해주면 sequelize project가 생성된다.
config/config.json
: DB의 정보를 담는 공간models/index.js
: DB의 테이블을 정의하는 곳 (MySQL의 Table에 대응)Migrations
: 테이블 컬럼을 추가/제거할 때 이 파일을 통해 실제 DB에 반영 (세미나에서 사용x)Seeders
: 시드 데이터를 생성하는 곳 (테스트 환경) (세미나에서 사용x)
MySQL Workbench의 RDS에서 Edit Connection - Hostname, Username, Password 확인, 이들을 config/config.json
에 잘 적어준다.
예: console로 DB 연결을 확인하는 코드 (App.js
에 추가)1
2
3
4
5
6
7
8
9const { sequelize } = require('./models');
sequelize.sync({ alter: false })
.then( () => {
console.log('데이터베이스 연결 성공');
})
.catch( (error) => {
console.error(error);
})
추가설명:
sequelize.sync({})
에서 모델 동기화가 시작된다! 테이블이 존재하지 않는 경우 생성함.sequelize.sync({force: true})
: 테이블이 이미 존재하면 삭제하고 생성sequelize.sync({alter: true})
: DB의 테이블 현재 상태(컬럼, DataType)를 확인하고 필요한 변경을 수행하여 모델과 일치시킴
Sequelize로 Model 정의하기
기본적으로는 다음과 같이 sequelize.define()
를 이용하여 정의한다.1
sequelize.define('모델이름', { /* 스키마 */ }, { /* 스키마 옵션 */ });
스키마 표기법은 다음과 같다:
모델의 옵션에는 다음과 같은 것들이 있다:
FreezeTableName
: true이면 모델명과 DB 테이블 이름을 동일하게 설정해줌. (Sequelize는 기본적으로 모델이름 - 단수, 테이블이름 - 복수 로 설정)timestamps
: 기본값 true, 자동으로 createdAt, updatedAt 컬럼 만들어줌.tableName
: 실제 DB의 테이블 이름 설정해줌.paranoid
: true로 설정하면 deletedAt라는 컬럼이 생기고, row를 삭제했을 때 실제 데이터는 삭제되지 않고 deletedAt에 지운 시간이 기록됨. 이러면 Select 할 때 집계 Xunderscored
: true이면 기본값 CamelCase에서 snake_case 로 바뀜.
Models/user.js
의 예시:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18module.exports = (sequelize, DataTypes) => {
return sequelize.define('User', {
// 모델의 Column 정의
email: {
type: DataTypes.STRING(30),
unique: true,
allowNull: false,
},
userName: {
type: DataTypes.STRING(200),
allowNull: false,
},
}, {
// 모델의 Option 정의
freezeTableName: true,
timestamps: false,
});
};
위의 예시와 같이 User Model을 만들면, Models/index.js
에서 다음과 같이 Sequelize 객체에 연결할 수 있다.
1 | cosnt db = {}; |
Sequelize Query
Sequelize 쿼리를 이용하여 CRUD 작업을 해보자!
예시들 (Sequelize query에서 const { User } = require('models/index.js 상대경로');
해줘야 함)
Create
SQL
INSERT INTO users (name, age, address) VALUES ('신연상', 21, '강남구');
Sequelize query
1
2
3
4
5
6// Model.create({ 정보 });
const user = await User.create( {
userName: '신연상',
age: 21,
address: '강남구',
});
findOne
SQL
select * from users LIMIT 1;
select * from users WHERE name = '신연상';
Sequelize query
1
2
3
4
5
6
7
8const user = await User.readOne({ });
// Model.findOne({ /* 읽을 로우 */ });
const user = await User.findOne({
where: {
name: '신연상',
},
});
findAll
SQL
select * from users;
select name, address from users where address = '강남구';
select age, name from users where age > 21;
Sequelize query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const user = await User.findAll({ });
// Model.findAll({ attributes, where });
const users = await User.findAll( {
attributes: ['name', 'address'],
where: {
address: '강남구'
}
});
const { Op } = require('sequelize');
const users = await User.findAll( {
attributes: ['age', 'name'],
where: {
age: { [Op.gt]: 21},
}
});
Update
SQL
update users set name = '바뀔이름' where id = 2;
Sequelize query
1
2
3
4
5
6// Model.update({ /* 수정할 내용 */ }, { /* 어떤 로우를 수정 */ });
const user = await User.update({ name: '바꿀 이름' }, {
where: {
id: 2
}
});
Destroy
SQL
delete from users where id = 2;
Sequelize query
1
2
3
4
5
6// Model.destroy({ /* 삭제할 로우 */ })
const user = await User.destroy( {
where: {
id: 2
}
});
참고사항들:
- Sequelize는 자체적으로 promise를 반환하기 때문에
async/await
사용 가능 - Sequelize 객체 내부의 Op 객체를 불러와 특수한 연산 사용 가능!
ex:Op.gt
(초과)Op.gte
(이상)Op.lt
(미만)Op.lte
(이하)Op.ne
(같지않음)Op.or
(또는)Op.in
(배열 요소 중 하나)Op.notIn
(배열 요소와 모두 다름)
[ON SOPT] Server 4th Seminar