데이터베이스와 연동해보자!

HanSH·2024년 1월 22일

NestJS

목록 보기
12/29

이전에는 Service에 테스트용 배열을 추가해 데이터 CRUD를 구현하였다.
이번에는 실제 데이터베이스와 연동을 해보도록 하자!

다만, 지금은 실습(연습)단계이므로 이번에 데이터베이스와 연동하는 것은 모듈을 새로 만들어서 하도록 한다.

사실 MariaDB나 MySQL이나 같은놈에서 나온거기때문에... 하는 법은 둘 다 똑같다.

MariaDB 설치

0. Docker는 이미 설치되어있다 가정한다.

윈도우에서 Docker를 사용하는 방법 윈도우의 경우 WSL을 먼저 설치하고 Docker를 설치해야한다. Docker가 기본적으로 리눅스 커널을 이용하다보니 어쩔 수 없다. docker vs virtual machine 깊게는 설명하지 않는다. docker - HostOS(커널)를 공유. 따라서 이미지가 가볍고 실행속도가 빠름. 하지만 HostOS가 오염된다면 각 컨테이너도 오염될 가능성이 높음
vm - 이미지에 각각의 OS를 포함. 따라서 이미지가 무겁고 실행속도가 느림. 하지만 OS를 공유하지 않으므로 완전 독립된 환경 구성 가능

1. 이미지 가져오기

docker pull mariadb 명령어를 통해 이미지를 가져온다.

2. 컨테이너 생성+실행하기

기본 명령어는 아래와 같다.
docker run -p <hostport>:3306 --name <name> -e MARIADB_ROOT_PASSWORD=<password> -d mariadb

  • -p : 포트
  • --name : 컨테이너 이름
  • -e : 환경변수
  • -d : 백그라운드로 실행

이를 실 사용 버전으로 바꾸면...
docker run -p 3306:3306 --name mariadb -e MARIADB_ROOT_PASSWORD=mysql1234 -d mariadb

만약 mysql을 설치해놓은 상태라면 host 3306포트는 사용하지 말자. 포트가 겹친다는 오류가 발생하며 실행이 안될 것이다.

3. 데이터베이스 접속

a. 컨테이너 접속
docker exec -it {컨테이너 이름} mariadb -uroot -p 로 접속하자.

b. DBeaver로 접속

Create Connection에서 위와 같이 설정을 한다.
Docker은 기본적으로 local에서 돌아가나 Host는 localhost, 포트와 비밀번호는 docker run에서 설정한 포트, 비밀번호를 입력하자.


잘 접속됨을 볼 수 있다.

4. TypeORM+MariaDB 패키지 설치

npm i --save @nestjs/typeorm typeorm mysql2 @nestjs/config
yarn add @nestjs/typeorm typeorm mysql2 @nestjs/config
둘 중 자신의 nest 설정에 맞게 설치하자. 나는 패키지매니저를 yarn으로 해서 두 번째 방법을 사용하였다.

  • @nestjs/typeorm - typeorm을 자동완성하게 해주는 패키지(
    vscode에서는?)
  • typeorm - typeorm을 node에서 인식하게 하는 패키지
  • mysql2 - mysql을 node에서 인식하게 하는 패키지
  • @nestjs/config - Environment를 사용하기 위한 패키지

5. MariaDB 연동 설정

먼저 루트 디렉터리에 env를 작성해주자.
나는 간단히 아래와 같이 작성하였다.

// ./.developement.env
DB_HOST=localhost
DB_PORT=3307
DB_USER=root
DB_PASS=mysql1234
DB_DATABASE=user

다음으로 module 설정을 해주도록 하자.

// app.module.ts
@Module({
  imports: [
    ... ,
    ConfigModule.forRoot( {
      envFilePath:['.development.env'] // env 파일 입력. 위치가 다른 경우 상대경로 입력
    }),
    TypeOrmModule.forRoot({
      type:"mysql",
      host:process.env.DB_HOST,
      port:parseInt(process.env.DB_PORT), // port는 int형으로
      username:process.env.DB_USER,
      password:process.env.DB_PASS,
      database:process.env.DB_DATABASE,
      entities: [User], // 기본 table 생성
      synchronize: true, // 전체 데이터를 Entity와 동일하게 만든다 === drop table + create table
    }),
    ...
  ],
  ...
})

6. 컨트롤러, 서비스, 모듈 만들기

a. 모듈을 만들어서
b. 컨트롤러를 등록하고
c. 메인 모듈에 import 시킨다

한땀한땀 만들기
nest g mo users // module 생성
nest g co users // controller 생성
nest g s  users // service 생성

이후 users.entity.ts를 만들어준다.

템플릿으로 만들기

nest g resource users

아래의 내용을 전부 자동으로 만들어준다.

> CREATE src/users/users.module.ts (224 bytes)
> CREATE src/users/users.resolver.spec.ts (525 bytes)
> CREATE src/users/users.resolver.ts (1109 bytes)
> CREATE src/users/users.service.spec.ts (453 bytes)
> CREATE src/users/users.service.ts (625 bytes)
> CREATE src/users/dto/create-user.input.ts (195 bytes)
> CREATE src/users/dto/update-user.input.ts (281 bytes)
> CREATE src/users/entities/user.entity.ts (187 bytes)
> UPDATE src/app.module.ts (312 bytes)

7. Entity 수정

간단한 Entity를 만들어보자.

// user.entity.ts
@Entity({name: 'user'}) // 테이블의 기본 이름 설정
export class User {
    @PrimaryGeneratedColumn()
    uid: number;

    @Column()
    id: string;

    @Column()
    password: string;

    @Column()
    email: string;

    @Column({default: 'default'})
    nickname: string;
}

8. controller, service를 수정

이 부분은 Github Repository를 참고 바란다.
작성하기에는 너무 길어서 Repository로 대체함을 양해 바란다.

Service에서 이 부분은 설명되어야 할 것 같아 작성한다.

  async update(id: number, user: UpdateUserDto) {
    const prevUser = await this.userRepository.findOne({
      where: {
        uid: id
      }
    });
    let userToUpdate = {...prevUser, ...user};
    await this.userRepository.save(userToUpdate);
  }
  • findOne.({where : ... }) : 어느 키를 기준으로 데이터를 찾을 것인지를 알려준다.
  • {...prevUser, ...user} : prevUser의 내용을 user의 데이터로 덮어쓴다.

여기까지 했다면 정상적으로 실행되고, /users/* 경로로 접속할 수 있을 것이다.

클라우드타입으로 배포

주의!!!! 배포할때는 app.module의 synchronize를 FALSE로 필히 바꾸자!!!!

1. 배포 전 MariaDB를 하나 만들어주자. 언제까지 local로 돌릴수는 없다.

Root Password에 env에 작성한 비밀번호를 적자.
Database Name에는 일단 users로 작성하자.

2. 다음으로 Repository에서 배포를 해보자.

환경변수에서 DB_HOST와 DB_PORT는 아래에 있는 내용을 적어주자.
<DB_HOST>:<DB_PORT>로 적혀있다. 아래의 사진에서는 host와 port는 다음과 같다.

  • DB_HOST: mariadb
  • DB_PORT: 3306

* 참고로 같은 프로젝트에 있다면 local로 잡혀서 컨테이너 이름으로도 접근할 수 있다.

3. 조금만 기다리면 배포가 완료된다.


링크를 눌러서 접속이 되는지 확인해보자.
Hello World!가 뜬다면 정상 동작하는 것이다!


이로서 TypeORM과 MariaDB를 이용한 Cloudtype 배포를 완료하였다.

참고

Cascade는 어떻게...?

TypeOrm에서 다:1의 관계를 할 때 cascade 관계를 어떻게 해야할지를 매우 고민하고, 여러 번 시행착오를 겪으며 결론을 얻어냈습니다.

1:1의 경우, @JoinColumn()의 여부에 따라 달라집니다.

@JoinColumn() 사용한 쪽에 onDelete: 'CASCADE'
사용하지 않은 쪽에 cascade: true

1:n의 경우,

many인 쪽에 onDelete: 'CASCADE'
one인 쪽에 cascade: true

n:m의 경우에는 대부분 중간 Table을 하나 만들어서 사용할 것으로 생각됩니다. 따라서 이 경우는 정리하지 않습니다.

profile
저는 말하는 싹 난 감자입니다

0개의 댓글