Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11743] ファイルの概要

このコミットは、Go言語の標準ライブラリである database/sql パッケージにおけるエラー名の変更に関するものです。具体的には、トランザクションが既に終了していることを示すエラー ErrTransactionFinishedErrTxDone にリネームしています。これは、より簡潔でGoらしい命名規則に合わせるための変更です。

コミット

commit 00651a2e6317230f85209a49a74cf466c29ec00c
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Fri Feb 10 09:12:32 2012 +1100

    database/sql: rename ErrTransactionFinished to ErrTxDone
    
    Part of issue 2843
    
    R=golang-dev, gri
    CC=golang-dev
    https://golang.org/cl/5646063

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/00651a2e6317230f85209a49a74cf466c29ec00c

元コミット内容

このコミットの元の内容は、database/sql パッケージ内で定義されていたエラー変数 ErrTransactionFinished の名称を ErrTxDone に変更することです。これに伴い、このエラーを参照しているすべての箇所も新しい名称に更新されています。

変更の背景

Go言語の標準ライブラリは、その設計原則として「シンプルさ」と「明瞭さ」を重視しています。エラーメッセージや変数名も例外ではありません。ErrTransactionFinished という名前は、その意味を明確に伝えていますが、Goの慣習としてはより簡潔な名前が好まれる傾向にあります。

この変更は、Goのイシュー2843の一部として行われました。当時のGoのイシュー管理システムや開発プロセスにおいて、コードベース全体の整合性や可読性を向上させるための継続的な取り組みの一環として、このようなリファクタリングが行われていました。ErrTxDoneErrTransactionFinished と同じ意味を持ちながら、より短く、Goの他のエラー名(例: io.EOF)との一貫性を持たせることを目的としています。

前提知識の解説

Go言語の database/sql パッケージ

database/sql パッケージは、Go言語でリレーショナルデータベースを操作するための汎用的なインターフェースを提供します。このパッケージ自体は特定のデータベースドライバーを含まず、データベース固有の操作は database/sql/driver インターフェースを実装した外部ドライバーによって行われます。

主要な概念は以下の通りです。

  • DB: データベースへの接続プールを表します。
  • Conn: データベースへの単一の接続を表します。
  • Tx: データベーストランザクションを表します。トランザクションは、複数のデータベース操作をアトミックな単位として実行するために使用されます。つまり、トランザクション内のすべての操作が成功するか、またはすべての操作が失敗してロールバックされるかのいずれかになります。
  • Stmt: プリペアドステートメントを表します。SQLインジェクション攻撃を防ぎ、クエリのパフォーマンスを向上させるために使用されます。

データベーストランザクション

データベーストランザクションは、データベース管理システム(DBMS)における一連の操作の論理的な単位です。トランザクションは、以下のACID特性を満たすことを保証します。

  • Atomicity(原子性): トランザクション内のすべての操作が完全に実行されるか、または全く実行されないかのどちらかです。部分的な実行は許されません。
  • Consistency(一貫性): トランザクションが開始されるとき、データベースは一貫した状態にあり、トランザクションが終了するときも一貫した状態にあります。
  • Isolation(独立性): 複数のトランザクションが同時に実行される場合でも、それぞれのトランザクションは他のトランザクションの影響を受けずに独立して実行されているように見えます。
  • Durability(永続性): トランザクションが一度コミットされると、その変更は永続的になり、システム障害が発生しても失われることはありません。

Goの database/sql パッケージでは、DB.Begin() メソッドでトランザクションを開始し、Tx.Commit() でコミット、Tx.Rollback() でロールバックします。トランザクションがコミットまたはロールバックされると、そのトランザクションオブジェクトは「終了」した状態になります。

Go言語のエラーハンドリング

Go言語では、エラーは多値戻り値の最後の値として返されるのが一般的です。慣習として、エラーがない場合は nil が返されます。エラーは error インターフェースを実装する型であり、通常は errors.New 関数で文字列からエラーを作成するか、カスタムエラー型を定義します。

このコミットで変更された ErrTransactionFinishedErrTxDone は、errors.New を使って作成されたグローバルなエラー変数です。これらのエラーは、トランザクションが既に終了しているにもかかわらず、そのトランザクションオブジェクトに対して操作を行おうとした場合に返されます。

技術的詳細

このコミットの技術的な変更は非常にシンプルで、主にシンボルのリネームです。

  1. エラー変数のリネーム: var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back") から var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back") へと変更されました。エラーメッセージ自体は変更されていません。

  2. 参照箇所の更新: src/pkg/database/sql/sql.go ファイル内で ErrTransactionFinished を参照しているすべての箇所が ErrTxDone に更新されました。これには、Tx 構造体のコメント、Tx.grabConn()Tx.Commit()Tx.Rollback()Tx.Query() メソッド内のエラーチェックが含まれます。

この変更は、コードの振る舞いには一切影響を与えません。純粋に命名規則の改善とコードベースの一貫性向上を目的としています。このようなリネームは、大規模なプロジェクトにおいてコードの保守性と可読性を維持するために定期的に行われる一般的なプラクティスです。

コアとなるコードの変更箇所

変更は src/pkg/database/sql/sql.go ファイルに集中しています。

--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -368,7 +368,7 @@ func (db *DB) Begin() (*Tx, error) {
 	}, nil
 }
 
-// DriverDatabase returns the database's underlying driver.
+// Driver returns the database's underlying driver.
 func (db *DB) Driver() driver.Driver {
 	return db.driver
 }
@@ -378,7 +378,7 @@ func (db *DB) Driver() driver.Driver {
 // A transaction must end with a call to Commit or Rollback.
 //
 // After a call to Commit or Rollback, all operations on the
-// transaction fail with ErrTransactionFinished.
+// transaction fail with ErrTxDone.
 type Tx struct {
 	db *DB
 
@@ -393,11 +393,11 @@ type Tx struct {
 
 	// done transitions from false to true exactly once, on Commit
 	// or Rollback. once done, all operations fail with
-// ErrTransactionFinished.
+// ErrTxDone.
 	done bool
 }
 
-var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back")
+var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
 
 func (tx *Tx) close() {
 	if tx.done {
@@ -411,7 +411,7 @@ func (tx *Tx) grabConn() (driver.Conn, error) {
 
 func (tx *Tx) grabConn() (driver.Conn, error) {
 	if tx.done {
-		return nil, ErrTransactionFinished
+		return nil, ErrTxDone
 	}
 	tx.cimu.Lock()
 	return tx.ci, nil
@@ -424,7 +424,7 @@ func (tx *Tx) releaseConn() {
 // Commit commits the transaction.
 func (tx *Tx) Commit() error {
 	if tx.done {
-		return ErrTransactionFinished
+		return ErrTxDone
 	}
 	defer tx.close()
 	return tx.txi.Commit()
@@ -433,7 +433,7 @@ func (tx *Tx) Commit() error {
 // Rollback aborts the transaction.
 func (tx *Tx) Rollback() error {
 	if tx.done {
-		return ErrTransactionFinished
+		return ErrTxDone
 	}
 	defer tx.close()
 	return tx.txi.Rollback()
@@ -550,7 +550,7 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
 // Query executes a query that returns rows, typically a SELECT.
 func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
 	if tx.done {
-		return nil, ErrTransactionFinished
+		return nil, ErrTxDone
 	}
 	stmt, err := tx.Prepare(query)
 	if err != nil {

この差分は、ErrTransactionFinished という文字列が ErrTxDone に置き換えられていることを明確に示しています。また、DB.Driver() メソッドのコメントも DriverDatabase から Driver に変更されていますが、これはこのコミットの主要な変更点ではありません。

コアとなるコードの解説

このコミットのコアとなる変更は、database/sql パッケージ内でトランザクションの状態を管理し、既に終了したトランザクションに対する操作を検出する部分にあります。

Tx 構造体には done というブール型のフィールドがあります。このフィールドは、トランザクションが Commit または Rollback されたときに true に設定されます。

変更前は、この done フィールドが true の場合、つまりトランザクションが既に終了している場合に、ErrTransactionFinished エラーが返されていました。

// 変更前
var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back")

func (tx *Tx) grabConn() (driver.Conn, error) {
	if tx.done {
		return nil, ErrTransactionFinished // ここでエラーを返す
	}
	// ...
}

func (tx *Tx) Commit() error {
	if tx.done {
		return ErrTransactionFinished // ここでエラーを返す
	}
	// ...
}
// 他のメソッドも同様

このコミットにより、ErrTransactionFinishedErrTxDone にリネームされたため、上記のコードは以下のように変更されました。

// 変更後
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")

func (tx *Tx) grabConn() (driver.Conn, error) {
	if tx.done {
		return nil, ErrTxDone // 新しいエラー名でエラーを返す
	}
	// ...
}

func (tx *Tx) Commit() error {
	if tx.done {
		return ErrTxDone // 新しいエラー名でエラーを返す
	}
	// ...
}
// 他のメソッドも同様

この変更は、database/sql パッケージを利用する開発者にとって、トランザクションが終了した際に受け取るエラーの名前が変わることを意味します。既存のコードで ErrTransactionFinished を直接参照している場合は、ErrTxDone に更新する必要があります。しかし、Goのエラーハンドリングの慣習として、特定のエラー変数に依存するよりも、エラー文字列をチェックするか、エラーをラップして型アサーションを行う方が柔軟性があります。このケースでは、エラーメッセージ自体は変わっていないため、エラーメッセージをチェックしているコードには影響がありません。

関連リンク

  • Go言語の database/sql パッケージのドキュメント: https://pkg.go.dev/database/sql
  • Go言語のエラーハンドリングに関する公式ブログ記事など(一般的な情報源)

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード(src/pkg/database/sql/sql.go
  • GitHubのコミット履歴
  • Go言語のイシュー追跡システム(当時のイシュー2843に関する詳細情報があれば)
  • Go言語のコードレビューシステム (Gerrit) のCL (Change List) 5646063: https://golang.org/cl/5646063