DataSource

ClassBinu·2024년 5월 19일

F-lab

목록 보기
25/65

DataSource

DataSource는 데이터베이스와의 상호작용을 관리하는 중심적인 객체. 이 객체를 통해 데이터베이스 연결 설정, 초기화, 연결 관리, 트랜잭션 처리, 쿼리 실행 등 데이터베이스 작업의 전반적인 흐름을 제어할 수 있습니다.

데이터베이스 상호작용은 데이터 소스를 설정한 후에만 가능함.
데이터베이스 연결 설정을 보유하고 있으며,
RDBMS에 따라 초기 데이터베이스 연결 또는 연결 풀을 설정함.

initialize 메서드로 연결이 설정되고,
destory 메서드로 연결 해제 됨.

일반적으로 앱의 부트스트랩 시에 DataSource 인스턴스의 initialize 메서드를 호출함.
당연히 앱이 동작할 때는 destroy하면 안 됨.

initialize

import { DataSource } from "typeorm"

const AppDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "test",
    password: "test",
    database: "test",
})

AppDataSource.initialize()
    .then(() => {
        console.log("Data Source has been initialized!")
    })
    .catch((err) => {
        console.error("Error during Data Source initialization", err)
    })

데이터 소스는 다양한 종류로 설정할 수 있다.

import { DataSource } from "typeorm"

const MysqlDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "test",
    password: "test",
    database: "test",
    entities: [
        // ....
    ],
})

const PostgresDataSource = new DataSource({
    type: "postgres",
    host: "localhost",
    port: 5432,
    username: "test",
    password: "test",
    database: "test",
    entities: [
        // ....
    ],
})

전역적으로 사용

import { AppDataSource } from "./app-data-source"
import { User } from "../entity/User"

export class UserController {
    @Get("/users")
    getAll() {
        return AppDataSource.manager.find(User)
    }
}

옵션

이건 빠르게 훑어보기

다중 데이터베이스

하나의 데이터 소스로 다중 디비를 쓸 수 있다!
이건 엔터티 명시할 때 옵션으로 어떤 디비를 쓸 건지 명시하면 됨.

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ database: "secondDB" })
export class User {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    firstName: string

    @Column()
    lastName: string
}
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity({ database: "thirdDB" })
export class Photo {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    url: string
}

이렇게 하면 그냥 엔터티만 제공해도 어떤 디비를 쓸지 정해짐.

const users = await dataSource
    .createQueryBuilder()
    .select()
    .from(User, "user")
    .addFrom(Photo, "photo")
    .andWhere("photo.userId = user.id")
    .getMany() // userId is not a foreign key since its cross-database request

다른 디비 간에는 외래키 제약 조건을 적용할 수 없음!

복제

복제본도 이렇게 간단하게 만들 수 있다고...?

const datasource = new DataSource({
  type: "mysql",
  logging: true,
  replication: {
    master: {
      host: "server1",
      port: 3306,
      username: "test",
      password: "test",
      database: "test"
    },
    slaves: [
      {
        host: "server2",
        port: 3306,
        username: "test",
        password: "test",
        database: "test"
      }, {
        host: "server3",
        port: 3306,
        username: "test",
        password: "test",
        database: "test"
      }
    ]
  }
});

의문
쓰기는 마스터로 보내고 읽기는 슬레이브로 보내는 걸 알겠음.
그럼 마스터 데이터 베이스가 실시간으로 슬레이브로 내려가게 하는 건 어떻게 처리해야 함?

데이터 소스 옵션

빠르게 훑어보기
예를 들어 이런거

await users = await manager.find()
await dataSource.initialize()
await dataSource.destroy()
await dataSource.synchronize()
await dataSource.dropDatabase()
await dataSource.runMigrations()
await dataSource.undoLastMigration()
if (dataSource.hasMetadata(User))
    const userMetadata = dataSource.getMetadata(User)
const userMetadata = dataSource.getMetadata(User)
const repository = dataSource.getRepository(User)
// now you can call repository methods, for example find:
const users = await repository.find()
const repository = dataSource.getTreeRepository(Category)
// now you can call tree repository methods, for example findTrees:
const categories = await repository.findTrees()
await dataSource.transaction(async (manager) => {
    // NOTE: you must perform all database operations using given manager instance
    // its a special instance of EntityManager working with this transaction
    // and don't forget to await things here
})
const rawData = await dataSource.query(`SELECT * FROM USERS`)
const users = await dataSource
    .createQueryBuilder()
    .select()
    .from(User, "user")
    .where("user.name = :name", { name: "John" })
    .getMany()

const queryRunner = dataSource.createQueryRunner()
await queryRunner.connect()
await queryRunner.release()

0개의 댓글