Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 1 | # Introduction |
| 2 | |
| 3 | The database/sql package provides a generic interface around SQL (or SQL-like) databases. See the [official documentation](http://golang.org/pkg/database/sql/) for details. |
| 4 | |
| 5 | This page provides example usage patterns. |
| 6 | |
| 7 | # Database driver |
| 8 | |
| 9 | The database/sql package must be used in conjunction with a database driver. |
| 10 | See http://golang.org/s/sqldrivers for a list of drivers. |
| 11 | |
| 12 | The documentation below assumes a driver has been imported. |
| 13 | |
| 14 | # Connecting to a database |
| 15 | |
| 16 | Open is used to create a database handle: |
| 17 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 18 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 19 | db, err := sql.Open(driver, dataSourceName) |
| 20 | ``` |
| 21 | |
| 22 | Where driver specifies a database driver and dataSourceName |
| 23 | specifies database-specific connection information |
| 24 | such as database name and authentication credentials. |
| 25 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 26 | Note that Open does not directly open a database connection: this is deferred until a query is made. To verify that a connection can be made before making a query, use the PingContext function: |
Konstantin Kulikov | c7758eb | 2015-08-08 12:48:54 +0300 | [diff] [blame] | 27 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 28 | ```go |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 29 | if err := db.PingContext(ctx); err != nil { |
Konstantin Kulikov | c7758eb | 2015-08-08 12:48:54 +0300 | [diff] [blame] | 30 | log.Fatal(err) |
| 31 | } |
| 32 | ``` |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 33 | |
| 34 | After use, the database is closed using Close. |
| 35 | |
| 36 | # Executing queries |
| 37 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 38 | ExecContext is used for queries where no rows are returned: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 39 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 40 | ```go |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 41 | result, err := db.ExecContext(ctx, |
gordonklaus | 0be401b | 2015-05-31 19:28:26 +0200 | [diff] [blame] | 42 | "INSERT INTO users (name, age) VALUES ($1, $2)", |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 43 | "gopher", |
| 44 | 27, |
| 45 | ) |
| 46 | ``` |
| 47 | |
| 48 | Where result contains the last insert ID and number of |
| 49 | rows affected. The availability of these values is dependent on |
| 50 | the database driver. |
| 51 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 52 | QueryContext is used for retrieval: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 53 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 54 | ```go |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 55 | rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age = $1", age) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 56 | if err != nil { |
| 57 | log.Fatal(err) |
| 58 | } |
Aseem Kishore | baf957a | 2018-06-17 15:23:43 -0400 | [diff] [blame] | 59 | defer rows.Close() |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 60 | for rows.Next() { |
| 61 | var name string |
| 62 | if err := rows.Scan(&name); err != nil { |
| 63 | log.Fatal(err) |
| 64 | } |
| 65 | fmt.Printf("%s is %d\n", name, age) |
| 66 | } |
| 67 | if err := rows.Err(); err != nil { |
| 68 | log.Fatal(err) |
| 69 | } |
| 70 | ``` |
| 71 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 72 | QueryRowContext is used where only a single row is expected: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 73 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 74 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 75 | var age int64 |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 76 | err := db.QueryRowContext(ctx, "SELECT age FROM users WHERE name = $1", name).Scan(&age) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 77 | ``` |
| 78 | |
| 79 | Prepared statements can be created with Prepare: |
| 80 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 81 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 82 | age := 27 |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 83 | stmt, err := db.PrepareContext(ctx, "SELECT name FROM users WHERE age = $1") |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 84 | if err != nil { |
| 85 | log.Fatal(err) |
| 86 | } |
| 87 | rows, err := stmt.Query(age) |
| 88 | // process rows |
| 89 | ``` |
| 90 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 91 | ExecContext, QueryContext and QueryRowContext can be called on statements. After use, a |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 92 | statement should be closed with Close. |
| 93 | |
| 94 | # Transactions |
| 95 | |
| 96 | Transactions are started with Begin: |
| 97 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 98 | ```go |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 99 | tx, err := db.BeginTx(ctx, nil) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 100 | if err != nil { |
| 101 | log.Fatal(err) |
| 102 | } |
| 103 | ``` |
| 104 | |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 105 | The ExecContext, QueryContext, QueryRowContext and PrepareContext functions already covered can be |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 106 | used in a transaction. |
| 107 | |
| 108 | A transaction must end with a call to Commit or Rollback. |
| 109 | |
| 110 | # Dealing with NULL |
| 111 | |
| 112 | If a database column is nullable, one of the types supporting null values should be passed to Scan. |
| 113 | |
| 114 | For example, if the name column in the names table is nullable: |
| 115 | |
Adrian Sieber | c97457c | 2017-06-06 06:38:06 +0000 | [diff] [blame] | 116 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 117 | var name NullString |
Daniel Theophanes | 19bdc05 | 2018-10-27 07:55:20 -0700 | [diff] [blame] | 118 | err := db.QueryRowContext(ctx, "SELECT name FROM names WHERE id = $1", id).Scan(&name) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 119 | ... |
| 120 | if name.Valid { |
| 121 | // use name.String |
| 122 | } else { |
| 123 | // value is NULL |
| 124 | } |
| 125 | ``` |
| 126 | |
| 127 | Only NullBool, NullFloat64, NullInt64 and NullString are implemented in |
| 128 | database/sql. Implementations of database-specific null types are left |
| 129 | to the database driver. |