github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/database/sql/example_test.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sql_test
     6  
     7  import (
     8  	"github.com/shogo82148/std/context"
     9  	"github.com/shogo82148/std/database/sql"
    10  	"github.com/shogo82148/std/fmt"
    11  	"github.com/shogo82148/std/log"
    12  	"github.com/shogo82148/std/strings"
    13  	"github.com/shogo82148/std/time"
    14  )
    15  
    16  func ExampleDB_QueryContext() {
    17  	age := 27
    18  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
    19  	if err != nil {
    20  		log.Fatal(err)
    21  	}
    22  	defer rows.Close()
    23  	names := make([]string, 0)
    24  
    25  	for rows.Next() {
    26  		var name string
    27  		if err := rows.Scan(&name); err != nil {
    28  
    29  			// スキャンエラーをチェックします。
    30  			// クエリの行はdeferで閉じられます。
    31  			log.Fatal(err)
    32  		}
    33  		names = append(names, name)
    34  	}
    35  
    36  	// データベースが書き込まれる場合は、ドライバから返されるCloseエラーを確認することを確実に行ってください。クエリは自動コミットエラーに遭遇し、変更をロールバックする必要がある場合があります。
    37  	rerr := rows.Close()
    38  	if rerr != nil {
    39  		log.Fatal(rerr)
    40  	}
    41  
    42  	// Rows.ErrはRows.Scanで遭遇した最後のエラーを報告します。
    43  	if err := rows.Err(); err != nil {
    44  		log.Fatal(err)
    45  	}
    46  	fmt.Printf("%s are %d years old", strings.Join(names, ", "), age)
    47  }
    48  
    49  func ExampleDB_QueryRowContext() {
    50  	id := 123
    51  	var username string
    52  	var created time.Time
    53  	err := db.QueryRowContext(ctx, "SELECT username, created_at FROM users WHERE id=?", id).Scan(&username, &created)
    54  	switch {
    55  	case err == sql.ErrNoRows:
    56  		log.Printf("no user with id %d\n", id)
    57  	case err != nil:
    58  		log.Fatalf("query error: %v\n", err)
    59  	default:
    60  		log.Printf("username is %q, account created on %s\n", username, created)
    61  	}
    62  }
    63  
    64  func ExampleDB_ExecContext() {
    65  	id := 47
    66  	result, err := db.ExecContext(ctx, "UPDATE balances SET balance = balance + 10 WHERE user_id = ?", id)
    67  	if err != nil {
    68  		log.Fatal(err)
    69  	}
    70  	rows, err := result.RowsAffected()
    71  	if err != nil {
    72  		log.Fatal(err)
    73  	}
    74  	if rows != 1 {
    75  		log.Fatalf("expected to affect 1 row, affected %d", rows)
    76  	}
    77  }
    78  
    79  func ExampleDB_Query_multipleResultSets() {
    80  	age := 27
    81  	q := `
    82  create temp table uid (id bigint); -- Create temp table for queries.
    83  insert into uid
    84  select id from users where age < ?; -- Populate temp table.
    85  
    86  -- First result set.
    87  select
    88  	users.id, name
    89  from
    90  	users
    91  	join uid on users.id = uid.id
    92  ;
    93  
    94  -- Second result set.
    95  select 
    96  	ur.user, ur.role
    97  from
    98  	user_roles as ur
    99  	join uid on uid.id = ur.user
   100  ;
   101  	`
   102  	rows, err := db.Query(q, age)
   103  	if err != nil {
   104  		log.Fatal(err)
   105  	}
   106  	defer rows.Close()
   107  
   108  	for rows.Next() {
   109  		var (
   110  			id   int64
   111  			name string
   112  		)
   113  		if err := rows.Scan(&id, &name); err != nil {
   114  			log.Fatal(err)
   115  		}
   116  		log.Printf("id %d name is %s\n", id, name)
   117  	}
   118  	if !rows.NextResultSet() {
   119  		log.Fatalf("expected more result sets: %v", rows.Err())
   120  	}
   121  	var roleMap = map[int64]string{
   122  		1: "user",
   123  		2: "admin",
   124  		3: "gopher",
   125  	}
   126  	for rows.Next() {
   127  		var (
   128  			id   int64
   129  			role int64
   130  		)
   131  		if err := rows.Scan(&id, &role); err != nil {
   132  			log.Fatal(err)
   133  		}
   134  		log.Printf("id %d has role %s\n", id, roleMap[role])
   135  	}
   136  	if err := rows.Err(); err != nil {
   137  		log.Fatal(err)
   138  	}
   139  }
   140  
   141  func ExampleDB_PingContext() {
   142  
   143  	// PingとPingContextは、データベースサーバーとの通信がまだ可能かどうかを判定するために使用されます。
   144  	//
   145  	// コマンドラインアプリケーションで使用する場合、Pingは追加クエリが可能であり、提供されたDSNが有効であることを確立するために使用できます。
   146  	//
   147  	// ロングランニングサービスで使用する場合、Pingはヘルスチェックシステムの一部となることがあります。
   148  
   149  	ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
   150  	defer cancel()
   151  
   152  	status := "up"
   153  	if err := db.PingContext(ctx); err != nil {
   154  		status = "down"
   155  	}
   156  	log.Println(status)
   157  }
   158  
   159  func ExampleDB_Prepare() {
   160  	projects := []struct {
   161  		mascot  string
   162  		release int
   163  	}{
   164  		{"tux", 1991},
   165  		{"duke", 1996},
   166  		{"gopher", 2009},
   167  		{"moby dock", 2013},
   168  	}
   169  
   170  	stmt, err := db.Prepare("INSERT INTO projects(id, mascot, release, category) VALUES( ?, ?, ?, ? )")
   171  	if err != nil {
   172  		log.Fatal(err)
   173  	}
   174  	defer stmt.Close() // 準備されたステートメントはサーバーリソースを消費するため、使用後は必ず閉じる必要があります。
   175  
   176  	for id, project := range projects {
   177  		if _, err := stmt.Exec(id+1, project.mascot, project.release, "open source"); err != nil {
   178  			log.Fatal(err)
   179  		}
   180  	}
   181  }
   182  
   183  func ExampleTx_Prepare() {
   184  	projects := []struct {
   185  		mascot  string
   186  		release int
   187  	}{
   188  		{"tux", 1991},
   189  		{"duke", 1996},
   190  		{"gopher", 2009},
   191  		{"moby dock", 2013},
   192  	}
   193  
   194  	tx, err := db.Begin()
   195  	if err != nil {
   196  		log.Fatal(err)
   197  	}
   198  	defer tx.Rollback() // もし関数内で後でトランザクションがコミットされた場合は、ロールバックは無視されます。
   199  
   200  	stmt, err := tx.Prepare("INSERT INTO projects(id, mascot, release, category) VALUES( ?, ?, ?, ? )")
   201  	if err != nil {
   202  		log.Fatal(err)
   203  	}
   204  	defer stmt.Close() // プリペアドステートメントはサーバーのリソースを使用するため、使用後は閉じるべきです。
   205  
   206  	for id, project := range projects {
   207  		if _, err := stmt.Exec(id+1, project.mascot, project.release, "open source"); err != nil {
   208  			log.Fatal(err)
   209  		}
   210  	}
   211  	if err := tx.Commit(); err != nil {
   212  		log.Fatal(err)
   213  	}
   214  }
   215  
   216  func ExampleDB_BeginTx() {
   217  	tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
   218  	if err != nil {
   219  		log.Fatal(err)
   220  	}
   221  	id := 37
   222  	_, execErr := tx.Exec(`UPDATE users SET status = ? WHERE id = ?`, "paid", id)
   223  	if execErr != nil {
   224  		_ = tx.Rollback()
   225  		log.Fatal(execErr)
   226  	}
   227  	if err := tx.Commit(); err != nil {
   228  		log.Fatal(err)
   229  	}
   230  }
   231  
   232  func ExampleConn_ExecContext() {
   233  
   234  	// *DBは接続のプールです。Connを呼び出して接続を予約し、専用で使用します。
   235  	conn, err := db.Conn(ctx)
   236  	if err != nil {
   237  		log.Fatal(err)
   238  	}
   239  	defer conn.Close() // プールに接続を返す。
   240  	id := 41
   241  	result, err := conn.ExecContext(ctx, `UPDATE balances SET balance = balance + 10 WHERE user_id = ?;`, id)
   242  	if err != nil {
   243  		log.Fatal(err)
   244  	}
   245  	rows, err := result.RowsAffected()
   246  	if err != nil {
   247  		log.Fatal(err)
   248  	}
   249  	if rows != 1 {
   250  		log.Fatalf("expected single row affected, got %d rows affected", rows)
   251  	}
   252  }
   253  
   254  func ExampleTx_ExecContext() {
   255  	tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
   256  	if err != nil {
   257  		log.Fatal(err)
   258  	}
   259  	id := 37
   260  	_, execErr := tx.ExecContext(ctx, "UPDATE users SET status = ? WHERE id = ?", "paid", id)
   261  	if execErr != nil {
   262  		if rollbackErr := tx.Rollback(); rollbackErr != nil {
   263  			log.Fatalf("update failed: %v, unable to rollback: %v\n", execErr, rollbackErr)
   264  		}
   265  		log.Fatalf("update failed: %v", execErr)
   266  	}
   267  	if err := tx.Commit(); err != nil {
   268  		log.Fatal(err)
   269  	}
   270  }
   271  
   272  func ExampleTx_Rollback() {
   273  	tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
   274  	if err != nil {
   275  		log.Fatal(err)
   276  	}
   277  	id := 53
   278  	_, err = tx.ExecContext(ctx, "UPDATE drivers SET status = ? WHERE id = ?;", "assigned", id)
   279  	if err != nil {
   280  		if rollbackErr := tx.Rollback(); rollbackErr != nil {
   281  			log.Fatalf("update drivers: unable to rollback: %v", rollbackErr)
   282  		}
   283  		log.Fatal(err)
   284  	}
   285  	_, err = tx.ExecContext(ctx, "UPDATE pickups SET driver_id = $1;", id)
   286  	if err != nil {
   287  		if rollbackErr := tx.Rollback(); rollbackErr != nil {
   288  			log.Fatalf("update failed: %v, unable to back: %v", err, rollbackErr)
   289  		}
   290  		log.Fatal(err)
   291  	}
   292  	if err := tx.Commit(); err != nil {
   293  		log.Fatal(err)
   294  	}
   295  }
   296  
   297  func ExampleStmt() {
   298  	// 通常使用時には、プロセスの開始時に1つのStmtを作成します。
   299  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   300  	if err != nil {
   301  		log.Fatal(err)
   302  	}
   303  	defer stmt.Close()
   304  
   305  	// クエリを発行する必要があるたびに再利用してください。
   306  	id := 43
   307  	var username string
   308  	err = stmt.QueryRowContext(ctx, id).Scan(&username)
   309  	switch {
   310  	case err == sql.ErrNoRows:
   311  		log.Fatalf("no user with id %d", id)
   312  	case err != nil:
   313  		log.Fatal(err)
   314  	default:
   315  		log.Printf("username is %s\n", username)
   316  	}
   317  }
   318  
   319  func ExampleStmt_QueryRowContext() {
   320  	// 通常の使用では、プロセス開始時に1つのStmtを作成します。
   321  	stmt, err := db.PrepareContext(ctx, "SELECT username FROM users WHERE id = ?")
   322  	if err != nil {
   323  		log.Fatal(err)
   324  	}
   325  	defer stmt.Close()
   326  
   327  	// クエリを発行するたびに再利用してください。
   328  	id := 43
   329  	var username string
   330  	err = stmt.QueryRowContext(ctx, id).Scan(&username)
   331  	switch {
   332  	case err == sql.ErrNoRows:
   333  		log.Fatalf("no user with id %d", id)
   334  	case err != nil:
   335  		log.Fatal(err)
   336  	default:
   337  		log.Printf("username is %s\n", username)
   338  	}
   339  }
   340  
   341  func ExampleRows() {
   342  	age := 27
   343  	rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age=?", age)
   344  	if err != nil {
   345  		log.Fatal(err)
   346  	}
   347  	defer rows.Close()
   348  
   349  	names := make([]string, 0)
   350  	for rows.Next() {
   351  		var name string
   352  		if err := rows.Scan(&name); err != nil {
   353  			log.Fatal(err)
   354  		}
   355  		names = append(names, name)
   356  	}
   357  	// 行を反復してエラーをチェックします。
   358  	if err := rows.Err(); err != nil {
   359  		log.Fatal(err)
   360  	}
   361  	log.Printf("%s are %d years old", strings.Join(names, ", "), age)
   362  }