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 }