Golang连接&操作mysql数据库

ゝ一纸荒年。 2023-09-29 18:30 80阅读 0赞

文章目录

  • 一、Golang连接&操作mysql数据库
    • 1.1 前置步骤
    • 1.2 测试查询和插入数据
    • 1.3 查询一个可空的列值
    • 1.4 处理多结果集
    • 1.5 Prepared statement

一、Golang连接&操作mysql数据库

1.1 前置步骤

  1. 这里使用github.com/go-sql-driver/mysql驱动包,需要导入
  2. 需要有一个数据库,创库创表用于测试。

    DROP TABLE IF EXISTS album;
    CREATE TABLE album (
    id INT AUTO_INCREMENT NOT NULL,
    title VARCHAR(128) NOT NULL,
    artist VARCHAR(255) NOT NULL,
    price DECIMAL(5,2) NOT NULL,
    PRIMARY KEY (id)
    );

    INSERT INTO album
    (title, artist, price)
    VALUES
    (‘Blue Train’, ‘John Coltrane’, 56.99),
    (‘Giant Steps’, ‘John Coltrane’, 63.99),
    (‘Jeru’, ‘Gerry Mulligan’, 17.99),
    (‘Sarah Vaughan’, ‘Sarah Vaughan’, 34.98);

1.2 测试查询和插入数据

  1. package main
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "log"
  6. "github.com/go-sql-driver/mysql"
  7. )
  8. var db *sql.DB
  9. type Album struct {
  10. ID int64
  11. Title string
  12. Artist string
  13. Price float32
  14. }
  15. func main() {
  16. cfg := mysql.Config{
  17. User: "root", //os.Getenv("DBUSER"),
  18. Passwd: "xwphs1234*", //os.Getenv("DBPASS"),
  19. Net: "tcp",
  20. Addr: "143.30.158.11:3306",
  21. DBName: "recordings",
  22. AllowNativePasswords: true,
  23. }
  24. // get a database handle
  25. var err error
  26. db, err = sql.Open("mysql", cfg.FormatDSN())
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. pingErr := db.Ping()
  31. if pingErr != nil {
  32. log.Fatal(pingErr)
  33. }
  34. fmt.Println("Connected!")
  35. albums, err := albumsByArtist("John Coltrane")
  36. if err != nil {
  37. log.Fatal(err)
  38. }
  39. fmt.Printf("Albums found: %v\n", albums)
  40. // Hard-code ID 2 to test the query
  41. alb, err := albumByID(2)
  42. if err != nil {
  43. log.Fatal(err)
  44. }
  45. fmt.Printf("Album found: %v\n", alb)
  46. // Album instance
  47. alb_instance := Album{
  48. Title: "The Modern Sound of Betty Carter",
  49. Artist: "Betty Carter",
  50. Price: 49.99,
  51. }
  52. // Add album data to the database
  53. albID, err := addAlbum(alb_instance)
  54. if err != nil {
  55. log.Fatal(err)
  56. }
  57. fmt.Printf("ID of added album: %v\n", albID)
  58. }
  59. // albumsByArtist queries for albums that have specified name.
  60. func albumsByArtist(name string) ([]Album, error) {
  61. // An albums slice to hold data from returned rows.
  62. var albums []Album
  63. rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name)
  64. if err != nil {
  65. return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
  66. }
  67. defer rows.Close()
  68. // Loop through rows, using Scan to assign column data to struct fields.
  69. for rows.Next() {
  70. var alb Album
  71. if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
  72. return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
  73. }
  74. albums = append(albums, alb)
  75. }
  76. if err := rows.Err(); err != nil {
  77. return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
  78. }
  79. return albums, nil
  80. }
  81. // albumByID queries for the album with the specified ID
  82. func albumByID(id int64) (Album, error) {
  83. // An album to hold data from returned row.
  84. var alb Album
  85. row := db.QueryRow("SELECT * FROM album where id = ?", id)
  86. if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
  87. if err == sql.ErrNoRows {
  88. return alb, fmt.Errorf("albumByID %d: no such album", id)
  89. }
  90. return alb, err
  91. }
  92. return alb, nil
  93. }
  94. // addAlbum adds the specified album to the database
  95. // returning the album ID of the new entry
  96. func addAlbum(alb Album) (int64, error) {
  97. result, err := db.Exec("INSERT INTO album (title, artist, price) VALUES (?, ?, ?)", alb.Title, alb.Artist, alb.Price)
  98. if err != nil {
  99. return 0, fmt.Errorf("addAlbum: %v\n", err)
  100. }
  101. id, err := result.LastInsertId()
  102. if err != nil {
  103. return 0, fmt.Errorf("addAlbum: %v\n", err)
  104. }
  105. return id, nil
  106. }

1.3 查询一个可空的列值

使用下图这种可以用来表示一个可空的值。
在这里插入图片描述

这里写了一个函数priceByID,返回一个指定ID的price值。如果price值为空则返回-1。
注意:这里price列值可以为空,所以使用sql.NullFloat64来接收。再通过price.Valid判断值是否为null。

  1. // priceByID get the price of album through specified ID.
  2. // if the return value is -1, it represents the column value is null.
  3. func priceByID(id int64) (float64, error) {
  4. // Price is an nullable column value, so we use sql.NullFloat64 to adopt it.
  5. var price sql.NullFloat64
  6. if err := db.QueryRow("SELECT price FROM album WHERE id = ?", id).Scan(&price); err != nil {
  7. if err == sql.ErrNoRows {
  8. return -1, fmt.Errorf("priceByID %d: no such album", id)
  9. }
  10. return -1, err
  11. }
  12. if price.Valid {
  13. return price.Float64, nil
  14. }
  15. return -1, nil
  16. }

然后是调用函数priceByID。这段接在1.2 main函数末尾

  1. // Get the price of album with ID 2
  2. price, err := priceByID(2)
  3. if err != nil {
  4. log.Fatal(err)
  5. }
  6. if price == -1 {
  7. fmt.Println("This column value is null")
  8. return
  9. }
  10. fmt.Printf("The price of album with ID 2 is %v\n", price)

1.4 处理多结果集

可以一次处理多个查询语句,然后放到结果集中。可以使用Rows.NextResultSet切换到下一个结果集。

这里db.Query一次处理两个查询语句,结果放到两个结果集中。

大坑:github.com/go-sql-driver/mysql 这个驱动的默认多语句执行是关掉的,所以数据库连接参数要指定:
MultiStatements: true

  1. // testMultipleResultSet is a test that query to return multiple result set
  2. func testMultipleResultSet() {
  3. rows, err := db.Query("SELECT * FROM album; SELECT * FROM song;")
  4. if err != nil {
  5. log.Fatal(err)
  6. }
  7. defer rows.Close()
  8. // Loop through the first result set
  9. var albums []Album
  10. for rows.Next() {
  11. var alb Album
  12. if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {
  13. log.Fatal(err)
  14. }
  15. albums = append(albums, alb)
  16. }
  17. fmt.Printf("Album found: %v\n", albums)
  18. // Advance to next result set
  19. rows.NextResultSet()
  20. // Loop through the second result set
  21. type Song struct {
  22. id int64
  23. name string
  24. artist string
  25. }
  26. var songs []Song
  27. for rows.Next() {
  28. var s Song
  29. if err := rows.Scan(&s.id, &s.name, &s.artist); err != nil {
  30. log.Fatal(err)
  31. }
  32. songs = append(songs, s)
  33. }
  34. fmt.Printf("Song found: %v\n", songs)
  35. }

1.5 Prepared statement

使用prepared statement使代码跑的更快一点。因为它避免了每次执行数据库操作时重复创建statement的开销。

  1. // preparedStatements retrieves the specified album by ID.
  2. // prepared statement run a bit faster by avoiding the overhead of re-creating statement each time performs database operation.
  3. func preparedStatements(id int) (Album, error) {
  4. // Define a prepared statement
  5. stmt, err := db.Prepare("SELECT * FROM album WHERE id = ?")
  6. if err != nil {
  7. log.Fatal(err)
  8. }
  9. var alb Album
  10. // Execute the parpared statement, passing an id value for the parameter where placeholder is ?.
  11. err = stmt.QueryRow(id).Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price)
  12. if err != nil {
  13. if err == sql.ErrNoRows {
  14. return alb, fmt.Errorf("preparedStatements %d: no such album", id)
  15. }
  16. return alb, err
  17. }
  18. return alb, nil
  19. }

发表评论

表情:
评论列表 (有 0 条评论,80人围观)

还没有评论,来说两句吧...

相关阅读