はじめに
こんにちは、ATOM開発グループの廣瀬七海です。 24新卒として入社し、バックエンドエンジニアとして働いております。
ATOMプロジェクトではGo言語を用いて開発を行っており、ORMとしてGORMを採用しています。 今回は、更新処理を実行する際にタイムスタンプ updated_at カラムが自動更新されないという問題に直面したため、その事例について紹介します。
問題
GORMには、レコード更新時にタイムスタンプを自動更新する機能があります。 通常、updated_at カラムを明示的に指定しなくても自動的に更新されるはずですが、updated_at カラムが自動更新されないという問題が発生しました。
原因
GORMのTableメソッドを使用していたことが原因でした。
参考:
更新処理における発行クエリ
GORMでは、DB操作の対象テーブルを指定する際に、ModelメソッドとTableメソッドという2つの方法があります。
これらのメソッドは発行されるクエリに影響するため、適切に使い分ける必要があります。
プロジェクトのソースコードではModelメソッドとTableメソッドが混在しており、それぞれの特徴を十分に理解していなかったため、「タイムスタンプが自動更新されない」という問題に直面しました。
以下では、データベースを用意して実際に発行されるクエリを確認していきます。
事前準備
今回紹介する事例を再現するために、簡単に事前準備を行います。
また、発行クエリの確認は以下の環境にて行います。
・バックエンド:Go言語
・データベース:MySQL
todoテーブルを作成
前提として、タイムスタンプはアプリ側で制御することとします。
そのため、DEFAULT CURRENT_TIMESTAMP
や ON UPDATE CURRENT_TIMESTAMP
は使用しません。
CREATE TABLE todo ( title VARCHAR(255), created_at TIMESTAMP, updated_at TIMESTAMP );
Todoモデルを用意
タイトルとタイムスタンプを持つ簡単なモデル構造体を用意します。
モデルを宣言する | GORM - The fantastic ORM library for Golang, aims to be developer friendly.
type Todo struct { Title string CreatedAt time.Time UpdatedAt time.Time }
Modelメソッドにおける発行クエリ
Modelメソッドでは、定義したモデル構造体に基づいてクエリが生成され、操作対象を指定します。このとき、定義したモデル構造体をGORMに伝えることができるため、updated_at カラムの更新について明示的に記述しなくても、自動で updated_at カラムを更新するクエリを発行してくれます。
db.Model(&Todo{}).Where("name = ?", "todo").Update("name", "updated todo")
UPDATE `todo` SET `title` = 'updated todo', `updated_at` = '2024-10-13 15:40:16.685' WHERE title = 'todo'
Tableメソッドにおける発行クエリ
Tableメソッドでは、テーブル名を用いて操作対象を指定します。 このメソッドではモデル構造体を渡さないため、GORMはモデル構造体の情報を把握できません。そのため、updated_at カラムの存在を認識できず、結果として updated_at カラムを更新するクエリは発行されません。
db.Table("todo").Where("name = ?", "todo").Update("name", "updated todo")
UPDATE `todo` SET `title` = 'updated todo' WHERE title = 'todo'
まとめ
今回はGORMでタイムスタンプが自動更新されない問題についてご紹介しました。
GORMなどのライブラリは非常に便利ですが、その仕様を十分に理解せずに使用すると、予期せぬバグの原因となる可能性があります。そのため、ライブラリの各メソッドの仕様をしっかりと把握した上で運用していくことが重要です。
同じような問題に直面された方は、ぜひ参考にしていただければと思います!