[インデックス 12437] ファイルの概要
このコミットは、Go言語の標準ライブラリである database/sql
パッケージにおけるドキュメントの追加に関するものです。具体的には、データベース接続の状態管理とコネクションプーリングに関する説明が追記されています。
コミット
- コミットハッシュ:
502e29f485c2a3ed5691601a689911199fd5aef0
- Author: Brad Fitzpatrick bradfitz@golang.org
- Date: Tue Mar 6 17:44:47 2012 -0800
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/502e29f485c2a3ed5691601a689911199fd5aef0
元コミット内容
database/sql: add docs about connection state, pooling
Fixes #3223
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5755063
変更の背景
この変更は、Goの database/sql
パッケージのドキュメントが、データベース接続の状態管理とコネクションプーリングの挙動について十分に説明していなかったという問題(Issue #3223)に対応するために行われました。特に、複数のゴルーチン間で *DB
オブジェクトを共有する際の注意点や、トランザクション内でのセッション状態の扱いについて、開発者が混乱する可能性があったため、より明確な説明が必要とされていました。
Issue #3223 のタイトルは「database/sql: document stateful / pooling rules better」であり、database/sql
パッケージにおけるステートフルな接続とプーリングのルールをより良く文書化することを目指していました。このコミットは、その要求に応える形で DB
型のコメントに詳細な説明を追加しています。
前提知識の解説
Goの database/sql
パッケージ
database/sql
パッケージは、Go言語でリレーショナルデータベースを操作するための汎用的なインターフェースを提供します。このパッケージ自体は特定のデータベースドライバの実装を含まず、データベースドライバは database/sql/driver
インターフェースを実装することで、このパッケージと連携します。これにより、アプリケーションコードは特定のデータベースシステムに依存することなく、統一されたAPIでデータベースにアクセスできます。
データベース接続の状態 (Connection State)
多くのリレーショナルデータベースシステムでは、接続ごとにセッション状態(session state)を持つことができます。セッション状態とは、特定の接続に紐付けられた設定や情報のことです。例えば、以下のようなものがセッション状態として管理されることがあります。
- トランザクション分離レベル: 読み取り一貫性、コミット済み読み取りなど。
- 自動コミットモード: 各SQL文が自動的にコミットされるか、明示的なコミットが必要か。
- ユーザー定義変数: セッション内で一時的に値を保持する変数。
- 文字セット: 接続で使用される文字エンコーディング。
- 一時テーブル: セッションが終了すると破棄される一時的なテーブル。
これらのセッション状態は、同じ接続を使い続ける限り維持されますが、接続が切断されたり、別の接続が使用されたりするとリセットされる可能性があります。
コネクションプーリング (Connection Pooling)
データベース接続の確立は、ネットワークオーバーヘッドや認証処理など、比較的コストの高い操作です。そのため、アプリケーションがデータベースに頻繁にアクセスする場合、接続を確立・切断するたびにこれらのコストが発生するとパフォーマンスが低下します。
コネクションプーリングは、この問題を解決するための一般的な手法です。コネクションプールは、事前に確立されたデータベース接続の集合を管理し、アプリケーションからの要求に応じて既存の接続を再利用します。これにより、接続の確立・切断のオーバーヘッドを削減し、アプリケーションのパフォーマンスを向上させることができます。
database/sql
パッケージは、内部的にコネクションプールを管理します。sql.Open
でデータベースを開くと、*DB
オブジェクトが返され、このオブジェクトがコネクションプールを管理します。アプリケーションは *DB
オブジェクトを通じてクエリを実行し、必要に応じて接続がプールから取得され、使用後にプールに戻されます。
技術的詳細
database/sql
パッケージの DB
型は、複数のゴルーチンによる同時使用に対して安全(safe for concurrent use by multiple goroutines
)であるとドキュメントされています。これは、DB
オブジェクト自体が内部的に同期メカニズムを持っており、複数のゴルーチンから同時にメソッドが呼び出されてもデータ競合が発生しないことを意味します。
しかし、このコミットで追加されたドキュメントは、この「安全」という言葉が、データベースドライバが持つ「接続ごとのセッション状態」の概念にまで及ばないことを明確にしています。
- コネクションプーリングの自動管理:
database/sql
パッケージは、基盤となるデータベースドライバが接続と接続ごとのセッション状態の概念を持っている場合、接続の作成と解放を自動的に管理します。これには、アイドル状態の接続のフリープールを維持することも含まれます。 - セッション状態の観察の注意点: もしアプリケーションが接続ごとのセッション状態を観察する必要がある場合、以下のいずれかの方法を取る必要があります。
*DB
を複数のゴルーチン間で共有しない: 各ゴルーチンが独自の*DB
インスタンスを持つことで、接続が混ざり合うことを防ぎ、セッション状態を予測可能にします。ただし、これはコネクションプーリングの利点を損なう可能性があります。- トランザクション内でのみ状態を管理する:
DB.Begin()
を呼び出してトランザクションを開始すると、返される*Tx
オブジェクトは単一の分離された接続にバインドされます。このトランザクションがコミットまたはロールバックされるまで、その接続は他のゴルーチンと共有されません。したがって、セッション状態の変更や観察は、このトランザクションのスコープ内で行うことで、他の操作の影響を受けずに済みます。トランザクションが終了すると、その接続はDB
のアイドルコネクションプールに戻されます。
このドキュメントの追加は、database/sql
パッケージの利用者が、コネクションプーリングの恩恵を受けつつも、データベースのセッション状態に依存するロジックを安全に実装するための重要な指針を提供します。特に、SET
コマンドなどでセッション変数を設定し、その後のクエリでその変数を参照するようなケースでは、トランザクション内で一連の操作を行うことが不可欠になります。
コアとなるコードの変更箇所
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -175,6 +175,16 @@ var ErrNoRows = errors.New("sql: no rows in result set")
// DB is a database handle. It's safe for concurrent use by multiple
// goroutines.
+//
+// If the underlying database driver has the concept of a connection
+// and per-connection session state, the sql package manages creating
+// and freeing connections automatically, including maintaining a free
+// pool of idle connections. If observing session state is required,
+// either do not share a *DB between multiple concurrent goroutines or
+// create and observe all state only within a transaction. Once
+// DB.Open is called, the returned Tx is bound to a single isolated
+// connection. Once Tx.Commit or Tx.Rollback is called, that
+// connection is returned to DB's idle connection pool.
type DB struct {
driver driver.Driver
dsn string
コアとなるコードの解説
追加されたコードは、DB
型のコメントブロックに10行の新しい説明を追加しています。
-
If the underlying database driver has the concept of a connection and per-connection session state, the sql package manages creating and freeing connections automatically, including maintaining a free pool of idle connections.
- これは、
database/sql
パッケージが、ドライバが接続とセッション状態の概念を持つ場合に、接続の作成、解放、およびアイドル接続のプール管理を自動的に行うことを説明しています。これはコネクションプーリングの基本的な挙動です。
- これは、
-
If observing session state is required, either do not share a *DB between multiple concurrent goroutines or create and observe all state only within a transaction.
- ここが最も重要な追加点です。もしアプリケーションがデータベースのセッション状態(例:
SET
コマンドで設定した変数など)を「観察」または「依存」する必要がある場合、2つの主要なアプローチを提示しています。do not share a *DB between multiple concurrent goroutines
: 複数のゴルーチン間で*DB
オブジェクトを共有しない。これは、各ゴルーチンが独自の*DB
インスタンスを持つことを意味し、接続の混同を防ぎますが、コネクションプーリングの利点を一部失う可能性があります。create and observe all state only within a transaction
: すべてのセッション状態の作成と観察をトランザクション内でのみ行う。これは、DB.Begin()
で開始されるトランザクションが単一の分離された接続にバインドされるため、そのトランザクション内でのセッション状態の変更が他の操作に影響を与えないことを保証します。
- ここが最も重要な追加点です。もしアプリケーションがデータベースのセッション状態(例:
-
Once DB.Open is called, the returned Tx is bound to a single isolated connection. Once Tx.Commit or Tx.Rollback is called, that connection is returned to DB's idle connection pool.
- この部分は、トランザクションのライフサイクルと接続の関連性を明確にしています。
DB.Begin()
(元のコメントではDB.Open
と誤記されている可能性がありますが、文脈からDB.Begin
を指していると解釈できます)が呼び出されると、返される*Tx
オブジェクトは、そのトランザクションの間、単一の分離された接続に排他的にバインドされます。トランザクションがTx.Commit
またはTx.Rollback
によって終了すると、その接続はDB
のアイドルコネクションプールに戻され、再利用可能になります。
- この部分は、トランザクションのライフサイクルと接続の関連性を明確にしています。
これらの追加されたコメントは、database/sql
パッケージの DB
型が「並行利用に安全」であることの意味をより深く掘り下げ、特にセッション状態に依存するアプリケーションロジックを記述する際のベストプラクティスと潜在的な落とし穴について、開発者に重要なガイダンスを提供しています。
関連リンク
- GitHub Issue: database/sql: document stateful / pooling rules better #3223
- Go CL (Code Review): https://golang.org/cl/5755063