TypeORM 0.3 ์ด์ ๋ฒ์ ์ ๊ธฐ์ค์ผ๋ก ํธ๋์ญ์ ์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํ์ต๋๋ค.
Transaction
- ํธ๋์ญ์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํ๊บผ๋ฒ์ ์ํ๋์ด์ผ ํ๋ ์์ ๋จ์๋ฅผ ๋งํฉ๋๋ค.
- ํธ๋์ญ์ ์ ์ค์ํ ํน์ง ์ค ํ๋๋ ํธ๋์ญ์ ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ๋ฐ์๋๋ ์ง, ์๋๋ฉด ์ ํ ๋ฐ์๋์ง ์์์ผ ํ๋ฉฐ ์์ ์ด ๋ถ๋ถ์ ์ผ๋ก ์คํ๋๊ฑฐ๋ ์ค๋จ๋์ง ์๋ ๊ฒ์ ๋ณด์ฅํ๋ ๊ฒ์ ๋๋ค. (ACID ์ค Atomicity, ์์์ฑ)
DataSource & EntityManager / QueryRunner
- TypeORM์์๋ DataSource & EntityManager ๋๋ QueryRunner๋ฅผ ํตํด ํธ๋์ญ์ ์ ์์ฑํ๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ค๋ช ํ๊ธฐ์ ์์, TypeORM์์์ DataSource, EntityManager, QueryRunner ์ธ ๊ฐ์ง ์ฉ์ด๋ฅผ ๋จผ์ ์ ๋ฆฌํด ๋ณด๊ฒ ์ต๋๋ค.
DataSource
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ , connection๊ณผ connection pool์ ์ค์ ํ๊ณ ๊ด๋ฆฌํ๋ ํด๋์ค์ ๋๋ค.
- DataSource ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ initialize๋ฅผ ์คํํ๋ฉด connection๊ณผ connectioin pool ๊ด๋ฆฌ๋ฅผ ์ํ ์ค์ ์ด ์ด๋ฃจ์ด์ง๋๋ค.
- ์ด๋ ํ๋์ DBMS์ ๋ํด ์ ์ญ์ ์ผ๋ก ํ๋์ ์ธ์คํด์ค๋ก ๊ด๋ฆฌ๋ฉ๋๋ค.
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);
});
EntityManager
- ๋ชจ๋ ์ํฐํฐ์ ๋ํด ์ฟผ๋ฆฌ๋ฅผ ์ํํ๋ API์, ํ๊บผ๋ฒ์ ์ํ๋์ด์ผ ํ๋ ์์ ๋ค์ ํธ๋์ญ์ ์ผ๋ก ๋ํํ๋ ๋ฉ์๋(= transaction)๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ด๋ ๋ชจ๋ ์ํฐํฐ์ repository๋ฅผ ํ ๊ณณ์ ๋ชจ์ ๊ฒ๊ณผ ๊ฐ์ ์ญํ ์ ํฉ๋๋ค.
- (์ฐธ๊ณ ) ํน์ ์ํฐํฐ์ ๋ํด ์ฟผ๋ฆฌ๋ฅผ ์ํํ๋ ค๋ฉด EntityManager๊ฐ ์๋๋ผ, dataSource.getRepository(User).findOneBy({ id: 1 }); ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ ๊ทผํด์ผ ํฉ๋๋ค.
import { DataSource } from "typeorm";
import { User } from "./entity/User";
const myDataSource = new DataSource(/*...*/);
const user = await myDataSource.manager.findOneBy(User, {
id: 1,
});
user.name = "Umed";
await myDataSource.manager.save(user);
- EntityManager๋ EntityMAnagerFactory๋ก๋ถํฐ ์์ฑ๋ฉ๋๋ค.
- DataSource ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ์ด๊ธฐํํ ๋ EntityManagerFactory์ create ๋ฉ์๋๊ฐ ์คํ๋๊ณ , ์ด๋ฅผ ํตํด ์๋ก์ด EntityManager ์ธ์คํด์ค๊ฐ DataSource ์ธ์คํด์ค์ manager ํ๋กํผํฐ์ ํ ๋น๋ฉ๋๋ค.
QueryRunner
- ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฑฐ๋ ๊ฐ๋ฐ์๊ฐ ํธ๋์ญ์ ์ ์ง์ ์ ์ผ๋ก ์ ์ดํ ์ ์๋๋ก ํ๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
- connection pool์ ์ง์ํ๋ RDBMS์ ๊ฒฝ์ฐ, connection pool์์ ํ๋์ connection์ ๊ฐ์ ธ์์ ์ฌ์ฉํ๋ ์ธํฐํ์ด์ค์ ๋๋ค. QueryRunner ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋๋ง๋ค connection pool์์ connection์ ๊ฐ์ ธ์์ ์ฌ์ฉํฉ๋๋ค.
- connection pool์ ์ง์ํ์ง ์๋ DBMS์ ๊ฒฝ์ฐ DataSource ์ ์ฒด์์ ํ๋์ connection์ ์ฌ์ฉํ์ฌ, QueryRunner ์ธ์คํด์ค๊ฐ ๊ฐ์ connection์ ๊ณต์ ํฉ๋๋ค.
- QueryRunner๋ ํด๋์ค๊ฐ ์๋๋ผ ์ธํฐํ์ด์ค์ด๊ณ , DBMS ๋ง๋ค์ ๊ตฌํ์ฒด ํด๋์ค๋ค์ด ์กด์ฌํ๊ณ ์์ต๋๋ค.
- ์ฃผ์ํ ์ ์ connection pool์์ ๋ค์ ์ฌ์ฉํ ์ ์๋๋ก ์ฟผ๋ฆฌ ์ํ ํ์ connection์ ๋ฐ๋ฉํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
TypeORM์ Transaction ์ ๋ต
1. DataSource & EntityManager Transaction
- ์ฑ์ ๋ถํธ์คํธ๋ฉ ํ ๋ ์์ฑํ DataSource ์ธ์คํด์ค์ 1) transaction ๋ฉ์๋ ๋๋ 2) manager ํ๋กํผํฐ์ transaction ๋ฉ์๋๋ก ํธ๋์ญ์ ์ ์ํํ ์ ์์ต๋๋ค.
await myDataSource.transaction(async (transactionalEntityManager) => {
await manager.save(users[0]);
await manager.save(users[1]);
});
// or
await myDataSource.manager.transaction(async (transactionalEntityManager) => {
await manager.save(users[0]);
await manager.save(users[1]);
});
- TypeORM์ GitHub ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด, ๋ ๋ฉ์๋๋ ์ฌ์ค ๊ฐ์ ์ผ์ ์ํํ๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
- DataSource ์ธ์คํด์ค๋ฅผ ์์ฑํ ๋ ์ํ๋๋ ์์ฑ์ ํจ์ ๋ด๋ถ์์, ์๋ก์ด EntityManager๋ฅผ ์์ฑํ์ฌ manager ํ๋กํผํฐ์ ํ ๋นํฉ๋๋ค.
- DataSource ํด๋์ค์ transaction ๋ฉ์๋์์๋, ํ์ฌ DataSource ์ธ์คํด์ค์ manager ํ๋กํผํฐ์ trasaction ๋ฉ์๋๋ฅผ ์ํํฉ๋๋ค.
- myDataSource.transaction()์ผ๋ก ์ ๊ทผํ๋ myDataSource.manager.transaction์ผ๋ก ์ ๊ทผํ๋ , ๊ฒฐ๊ตญ myDataSource.manager.transaction()์ ์ํํ๋ ๊ฒ์ ๋๋ค. (EntityManager ํด๋์ค์ transaction ๋ฉ์๋)
- ์ฃผ์ํด์ผ ํ ์ ์ ์ฝ๋ฐฑ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ฃผ์ด์ง๋ EntityManager๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ์ํํด์ผ ํ๋ค๋ ๊ฒ์
๋๋ค.
- EntityManager ํด๋์ค์ tranasction ๋ฉ์๋ ๋ด๋ถ๋ฅผ ์ดํด๋ณด๋ฉด, ์๋ก์ด QueryRunner๋ฅผ ์์ฑํ๊ณ ์์ต๋๋ค.
- ๋ํ DataSource ํด๋์ค์ createQueryRunner ๋ฉ์๋๋ฅผ ๋ฐ๋ผ๊ฐ๋ณด๋ฉด, ํ์ฌ DBMS ๋๋ผ์ด๋ฒ์ ๋ง๋ QueryRunner๋ฅผ ์์ฑํ๊ณ ์์ต๋๋ค. ๋ํ, ์์ฑ๋ QueryRunner์ manager ํ๋กํผํฐ์ ์๋ก์ด EntityManager ๊ฐ์ฒด๋ฅผ ํ ๋นํ๊ณ ์์ต๋๋ค.
- dataSource.manager.trasaction()์ ์ฝ๋ฐฑ ํจ์๋ก ์ ๋ฌ๋๋ EntityManager๋, DataSource์ manager ํ๋กํผํฐ์ ํ ๋น๋ ์ ์ญ EntityManager๊ฐ ์๋๋ผ QueryRunner์ EntityManager์ธ ๊ฒ์ ๋๋ค. (์๋ก ๋ค๋ฆ!)
- DataSource ๋๋ DataSource์ EntityManager์ ํธ๋์ญ์ ๋ฉ์๋๋ก ํธ๋์ญ์ ์ ์ํํ ๊ฒฝ์ฐ, ๋ด๋ถ์ ์ผ๋ก QueryRunner๋ฅผ ์์ฑํ์ฌ commit, rollback, connection ๋ฐ๋ฉ๊น์ง ํด์ฃผ๊ณ ์๋ ๊ฒ์ ๋๋ค.
2. QueryRunner Transaction
- ์๋์ผ๋ก QueryRunner๋ฅผ ์์ฑํ์ฌ
- ์ง์ SQL ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฑฐ๋,
- EntityManager API๋ก ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฑฐ๋,
- ํธ๋์ญ์ ์ ์ง์ ์ ์ดํ ์ ์์ต๋๋ค.
const queryRunner = dataSource.createQueryRunner();
await queryRunner.connect();
// 1. ์ง์ SQL ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฑฐ๋
await queryRunner.query("SELECT * FROM users");
// 2. EntityManager API๋ก ์ฟผ๋ฆฌ๋ฅผ ์ํํ๊ฑฐ๋
const users = await queryRunner.manager.find(User);
// 3. ํธ๋์ญ์
์ ์ ์ดํ ์ ์๋ค.
await queryRunner.startTransaction();
try {
// ํธ๋์ญ์
์์
๋ค...
await queryRunner.manager.save(user1);
await queryRunner.manager.save(user2);
// commit
await queryRunner.commitTransaction();
} catch (err) {
// ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด rollback
await queryRunner.rollbackTransaction();
} finally {
// ์์ฑํ QueryRunner ํด์ฒด(connection ๋ฐ๋ฉ)
await queryRunner.release();
}
๊ทธ๋์ ์ด๋ค ๊ฑธ ์ฐ๋ผ๋ ๊ฒ์ธ๊ฐ !?
- DataSource์ transaction ๋ฉ์๋๋ ์๋์ ์ผ๋ก ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋ ํจ๊ณผ๊ฐ ์์ง๋ง, ์ง์ ์ ์ผ๋ก ํธ๋์ญ์ ์ ๋ค๋ฃฐ ์ ์์ต๋๋ค.
- QueryRunner๋ ์ง์ ํธ๋์ญ์ ์ ์ ์ดํ ์ ์์ง๋ง, ์ค๋ณต๋๋ ์ฝ๋๊ฐ ๋ง์์ง๊ณ ํธ๋์ญ์ ๊ด๋ฆฌ์ ๋ํ ์ฑ ์์ด ๋ฐ๋ฆ ๋๋ค.
- NestJS ํ๋ ์์ํฌ์์๋ TypeORM์ ํธ๋์ญ์ ์ ๋ค๋ฃจ๋ ์ ๋ต ์ค ์ง์ ํธ๋์ญ์ ์ ์ ์ดํ ์ ์๋ QueryRunner๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๊ณ ์์ต๋๋ค. [์ฐธ๊ณ ]
- ๊ฐ์ธ์ ์ ์๊ฐ์ผ๋ก๋ QueryRunner๋ก ํธ๋์ญ์ ์ ์ง์ ์ ์ดํ๋, ์ค๋ณต๋๋ ์ฝ๋๋ฅผ ์ค์ผ ์ ์๋ ๋ฆฌํฉํฐ๋ง ๋ฐฉ๋ฒ์ ์ฐพ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
(๋ฒ์ธ) TypeORM์ Connection์ ์ DataSource๋ก ๋ฐ๊ฟจ์๊น?
- TypeORM 0.2.x ๋ฒ์ ์์ Connection์ 0.3.0 ๋ฒ์ ๋ถํฐ deprecated ๋๊ณ , ์ง๊ธ์ DataSource๋ก ๋ฐ๋์์ต๋๋ค. [์ฐธ๊ณ ]
- TypeORM ๊ฐ๋ฐ์๊ฐ ์ฌ๋ฆฐ issue๋ฅผ ๋ณด๋ฉด, Connection ์ด๋ผ๋ ์ด๋ฆ์ด ์ ์ ํ์ง ์์ผ๋ฉฐ, DataSource ๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค๊ณ ์ด์ผ๊ธฐ ํฉ๋๋ค.
- ์ด์ ์ Connection ์ด๋ผ๋ ๋ช ์นญ์ ์ค์ ๋ก connection์ ์๋ฏธํ์ง ์์ผ๋ฉฐ, ๊ทธ์ DBMS ์ฐ๊ฒฐ ์ค์ ์ ๊ดํ ๊ฐ์ฒด์ผ ๋ฟ์ด๋ผ๊ณ ํฉ๋๋ค. ์ค์ connection์ ์๋ฏธํ๋ ๊ฒ์ QueryRunner ์ ๋๋ค.
๊ทธ๋ผ ์ DataSource ์ผ๊น?
- Java์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ์ ์๋๋ก ํ๋ API์ธ JDBC(Java Database Connectivity)์ DataSource๋ผ๋ ์ธํฐํ์ด์ค๊ฐ ์์ต๋๋ค. DataSource ์ธํฐํ์ด์ค๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ๊ณผ connection์ ์ป๋ ๊ณผ์ ์ ์ถ์ํํ๋๋ฐ, DataSource ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํฉ๋๋ค. ๋ํ์ ์ผ๋ก Spring์์๋ HikariCP connection pool์ ๊ธฐ๋ฐ์ผ๋ก ํ HikariDataSource๋ฅผ ์ ๊ณตํฉ๋๋ค.
- (์ฐธ๊ณ ) JPA์๋ EntityManager๋ผ๋ ๊ฐ๋ ์ด ์์ต๋๋ค. connection์ ์ป์ด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉํ๊ณ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ๊ด๋ฆฌํ๋ ์ญํ ์ ๋๋ค. TypeORM์๋ ์์์ฑ ์ปจํ ์คํธ, 1์ฐจ ์บ์์ ๊ฐ๋ ์ด ์๋์ง๋ ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ๊ณต์๋ฌธ์ ์์์๋ ์์์ฑ ์ปจํ ์คํธ์ ์ญํ (1์ฐจ ์บ์์ ์ํฐํฐ ์์ํ)์ ํ๋ ๊ฐ๋ ์ ์ฐพ์ ์ ์์์ต๋๋ค.
- TypeORM์ ์ฌ๋ฌ ๊ฐ๋ ๋ค์ ์๋์ ์ผ๋ก ์ญ์ฌ๊ฐ ๋ ์ค๋๋ Java์ JPA์์ ๋ง์ ๋ถ๋ถ ์ฐจ์ฉํด์ ๋ง๋ค์ด์ก๋ค๊ณ ์๊ฐ์ด ๋ญ๋๋ค. NodeJS์์ ์ฌ์ฉํ ์ ์๋ ๋ ๋ค๋ฅธ ORM ๊ธฐ์ ์ค ํ๋์ธ Prisma์์๋ JPA, TypeORM์์์ DataSource์ ๊ฐ์ ์๋ฏธ๋ก DataSource API๊ฐ ์์ต๋๋ค.
์ฐธ๊ณ
- https://github.com/typeorm/typeorm/issues/8010
- https://typeorm.io/data-source
- https://typeorm.io/working-with-entity-manager
- https://typeorm.io/query-runner
- https://typeorm.io/transactions
- https://taler.tistory.com/12
- https://opentutorials.org/module/3569/21223
- https://tecoble.techcourse.co.kr/post/2023-06-28-JDBC-DataSource/
- https://shuu.tistory.com/130
- https://dangdangee.tistory.com/entry/DB-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80Connection-Pool%EA%B3%BC-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%86%8C%EC%8A%A4DataSource#google_vignette
- https://www.prisma.io/docs/orm/prisma-schema/overview/data-sources
'๋ฐฑ์๋ > ORM' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[TypeORM] bigint๊ฐ string์ผ๋ก ๋ณํ๋ ๋ (0) | 2024.10.25 |
---|---|
[TypeORM] ์ ์ํฐํฐ ํด๋์ค ํ๋กํผํฐ๋ฅผ private์ผ๋ก ํ ์ ์์๊น? (0) | 2024.09.09 |