TypeORM

【危険】TypeORMのsynchronizeには注意!!

【危険】TypeORMのsynchronizeには注意!!

TypeScriptやJavaScriptのORMであるTypeORMを使っている中で、これは危険だ。。と思う挙動に遭遇したので共有しておきます。

少しでもTypeORMを使って開発を進めていこうと思っている方の参考になれば幸いです。

バージョン情報
  • Node:v18.9.0
  • TypeORM:0.3.9

【危険】TypeORMのsynchronizeには注意!!

それでは早速、TypeORMの危険な挙動を紹介していきます。

 

現状は、以下のcountriesテーブルに対して、TypeORMを使ってデータ操作をしたい状況です。

countriesテーブル

 

まずは、countriesテーブルに対応するModelを定義します。

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

@Entity('countries')
export class Country {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    // countriesテーブルのカラム定義が足りない
}

 

ここでのポイントは、countriesテーブルのカラムの一部が定義されていない点です。

これが後の「事故」に繋がっていきます。。

 

そして、data-source.tsにDBとの接続情報等を定義し、最後にinitializeメソッドを呼び出します。

import "reflect-metadata"
import { DataSource } from "typeorm"
import { Country } from "./entity/Country"

export const AppDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "user",
    password: "pass",
    database: "database",
    synchronize: true,
    logging: false,
    entities: [Country],
    migrations: [],
    subscribers: [],
})

 

import { AppDataSource } from "./data-source"

AppDataSource.initialize()

 

 

これで準備が整ったので、以下のコマンドを実行します。

npm start

 

AppDataSource.initializeメソッドが実行されます。

 

この状況でcountriesテーブルを見てみると、、

データが消えたcountriesテーブル

 

なんと、idとname以外のカラムが消え、データも消滅してしまっています。。

 

なぜ、このような事態になってしまったのでしょうか。

ポイントは、以下のdata-source.tsの定義にあります。

import "reflect-metadata"
import { DataSource } from "typeorm"
import { Country } from "./entity/Country"

export const AppDataSource = new DataSource({
    type: "mysql",
    host: "localhost",
    port: 3306,
    username: "user",
    password: "pass",
    database: "database",
    synchronize: true,
    logging: false,
    entities: [Country],
    migrations: [],
    subscribers: [],
})

 

このように、synchronizeがtrueの設定になっていると、initializeメソッドが走ったときに、Modelの定義と実際のテーブルが同期(synchronize)されてしまうのです。

 

今回は、Modelの定義が実際のテーブルと合っていない状態でinitializeメソッドが走ったため、データが消えてしまいました。。

 

この挙動については、公式にも以下のように記述されています。

This option automatically syncs your database tables with the given entities each time you run this code. This option is perfect during development, but in production you may not want this option to be enabled.

このオプションは、このコードを実行するたびに、指定されたエンティティでデータベーステーブルを同期このオプションは開発時には最適ですが、実稼働時にはこのオプションを有効にしておきたくないかもしれません。

DeepL

 

万が一ローカルから本番環境のDBに接続してしまっていたら、大事故になってしまいます。

恐ろしすぎますね。。

 

実際この設定を有効にしてしまっていたせいで本番環境のデータを吹っ飛ばしたエンジニアがいたとかいなかったとか。。

 

【危険】TypeORMのinitializeには注意!! おわりに

TypeORMでこのような事故が起こるのを避けるには、以下のような対策が有効なのではないかと考えます。

  • synchronizeオプションを無効にしておく
  • ローカルから本番環境やステージング環境のDBに繋がない
  • 注意を促すコメントを書いておく
  • Prisma等別のORMを使う

 

synchronizeは、場合によっては便利な機能なのかもしれませんが、個人的にはかなり危険な機能なのかなと思っています。(正直無い方がいいのではと思っています。。)

 

とはいえTypeORMは人気のORMマッパーではあるので、業務で使うこともあるでしょう。

その際は、しっかりと設定を確認して、事故を未然に防ぐようにしましょう。

 

最後まで読んでいただきありがとうございました。

この記事がTypeORMを使う上で少しでも参考になっていれば幸いです。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA