Spring Bootでデータベースのコネクションをフィールドに保持すべきではない理由と正しい管理方法

こんにちは。ゆうせいです。

新人研修中に受講者から以下の質問をいただきました。

Spring Bootでデータベースのコネクションをフィールドに保持すべきではないのはなぜですか?

今回はこの質問に答えたいと思います。

Spring Bootを使用してアプリケーションを開発する際、データベースとの接続を管理するコネクションオブジェクトの扱い方には注意が必要です。クラスのフィールドにコネクションを定義して保持することは、推奨されていません。今回は、なぜフィールドに保持してはいけないのか、その理由と適切な管理方法について解説します。

Spring Bootの部品が持つ共有の性質

Spring Bootでは、コントローラーやサービス、リポジトリといったクラスのインスタンスは、原則としてアプリケーション内で1つだけ生成され、使い回される仕組みになっています。この仕組みをシングルトンと呼びます。

アプリケーションに対して同時に複数のユーザーからアクセスがあった場合、Spring Bootは複数のスレッドを立ち上げて処理を行います。しかし、処理を行うクラス自体は1つしか存在しないため、複数のスレッドが同時に同じインスタンスへアクセスすることになります。

データベースコネクションをフィールドに持つと発生する問題

クラスのフィールドにデータベースのコネクションを定義すると、すべてのスレッドが同じコネクションを共有して使用することになります。

ここで、高校生の図書室の利用を例に挙げてみましょう。図書室の貸出カウンターに、外部のシステムと通信するためのパソコンが1台だけ置いてあるとします。このパソコンがデータベースのコネクションに該当します。

複数の図書委員が同時に別々の生徒の貸出処理を行おうとして、全員で1台のパソコンのキーボードを同時に叩き始めたらどうなるでしょうか。画面に入力される文字は混ざり合い、誰の処理を行っているのか分からなくなってしまいます。

データベースのコネクションも同様です。コネクションは複数の処理を同時に行うようには作られていません。1つのスレッドがデータを更新している最中に、別のスレッドがその接続を使って別のデータを読み込もうとすると、データの混濁やエラーが発生します。また、一方のスレッドが処理を確定(コミット)した瞬間に、もう一方のスレッドの処理まで意図せず確定してしまうという現象も引き起こされます。

フィールドに保持しない場合の具体的なメリットとデメリット

コネクションをフィールドに保持せず、必要なときにだけ取得して使い終わったら破棄する、あるいはコネクションプールという仕組みで適切に管理する場合のメリットとデメリットは以下の通りです。

メリット

  • 複数のアクセスが同時に発生しても、それぞれの処理が独立したコネクションを使用するため、データが混ざり合う心配がありません。
  • データの確定や取り消しといったトランザクション管理が、それぞれのユーザーの処理ごとに独立して実行されます。
  • 1つの接続でエラーが発生して切断されても、他のユーザーの処理に影響を与えることがありません。

デメリット

  • 処理ごとに接続を確保して解放するための管理記述が、プログラム内に必要となります。
  • 接続の取得と破棄を適切に行わないと、接続が残ったままになり、データベース側の接続上限に達してしまうリスクがあります。ただし、Spring Bootの標準的な機能を利用すれば、この接続管理は自動化されます。

推薦される実装方法

Spring Bootでは、コネクションをクラスのフィールドとして保持するのではなく、メソッドの内部でローカル変数として扱うか、Springが提供するデータアクセスライブラリを活用します。

例えば、JdbcTemplateやSpring Data JPAといった機能を使用すると、開発者が手動でコネクションを管理する必要がなくなります。以下に、データアクセスの実装例を示します。

@Repository
public class UserRepository {
    private final JdbcTemplate jdbcTemplate;

    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public User findById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
    }
}

このように、JdbcTemplateをフィールドに持つことは安全です。JdbcTemplateは、内部でスレッドごとに異なるコネクションを適切に割り当てる設計になっているため、複数のアクセスが同時に発生しても問題は起きません。

まとめと今後の学習ステップ

Spring Bootでデータベースコネクションをフィールドに保持してはいけない理由は、複数のスレッドから同時に同じ接続が使用されることで、処理の衝突やデータの破壊が起きるためです。

安全なアプリケーションを開発するために、以下のステップに沿って学習を進めてみてください。

  1. スレッドとシングルトンの関係性を学ぶまず、Webアプリケーションが同時に複数の処理をどのように並行して実行しているのか、その仕組みへの理解を深めてください。
  2. コネクションプールの仕組みを理解する毎回接続を作るのではなく、あらかじめ用意された接続のプールから必要な分だけ借りて返す、コネクションプールの概念を学んでください。Spring BootではHikariCPという仕組みが標準で動いています。
  3. Spring Data JPAなどのフレームワークに触れる直接データベースの接続を操作するのではなく、フレームワークがどのように接続を隠蔽し、安全に管理してくれているのかを、実際にコードを書きながら体験してください。

仕組みを丁寧に紐解いていくことで、堅牢なシステム開発の技術が身につきます。

セイ・コンサルティング・グループでは新人エンジニア研修のアシスタント講師を募集しています。

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。

学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。