Golang开发X功能包的实现方案求反馈

Golang开发X功能包的实现方案求反馈 你好,

我正在开发一个用于X的Go包。有人可以审查一下我的代码吗?

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "user:password@tcp(database-server:3306)/database-name")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	var (
		id   int
		name string
		age  int
	)

	rows, err := db.Query("SELECT id, name, age FROM users WHERE age > ?", 18)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&id, &name, &age)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
	}

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
}

提前感谢。


更多关于Golang开发X功能包的实现方案求反馈的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

@tonnytg

感谢你的回复。非常感谢你的支持。

更多关于Golang开发X功能包的实现方案求反馈的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


不要在Go文件中硬编码连接信息。 将连接参数放在文件中并读取该文件。 大多数程序都需要配置参数,因此您可以将连接字符串作为参数放入此类文件中。

这是一个典型的Go语言数据库查询实现,代码结构基本正确,但有几个可以改进的地方:

1. 连接池配置

建议显式配置连接池参数,避免使用默认值:

db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5 * time.Minute)

2. 错误处理优化

rows.Err()应该在循环后检查,但你的代码已经正确实现了这一点。不过可以更明确地处理不同类型的错误:

if err := rows.Err(); err != nil {
    log.Printf("Error iterating rows: %v", err)
    return
}

3. 使用结构体映射

对于查询结果,使用结构体可以提高代码可读性:

type User struct {
    ID   int
    Name string
    Age  int
}

func queryUsers(db *sql.DB, minAge int) ([]User, error) {
    rows, err := db.Query("SELECT id, name, age FROM users WHERE age > ?", minAge)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []User
    for rows.Next() {
        var u User
        if err := rows.Scan(&u.ID, &u.Name, &u.Age); err != nil {
            return nil, err
        }
        users = append(users, u)
    }
    
    if err := rows.Err(); err != nil {
        return nil, err
    }
    
    return users, nil
}

4. 连接字符串提取

建议将数据库连接字符串提取为配置:

type Config struct {
    DBUser     string
    DBPassword string
    DBHost     string
    DBPort     string
    DBName     string
}

func (c *Config) DSN() string {
    return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true",
        c.DBUser, c.DBPassword, c.DBHost, c.DBPort, c.DBName)
}

5. 完整的改进示例

package main

import (
    "database/sql"
    "fmt"
    "log"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

type Database struct {
    *sql.DB
}

func NewDatabase(dsn string) (*Database, error) {
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        return nil, fmt.Errorf("failed to open database: %w", err)
    }

    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(25)
    db.SetConnMaxLifetime(5 * time.Minute)

    if err := db.Ping(); err != nil {
        return nil, fmt.Errorf("failed to ping database: %w", err)
    }

    return &Database{db}, nil
}

func (db *Database) GetUsersByMinAge(minAge int) ([]User, error) {
    const query = "SELECT id, name, age FROM users WHERE age > ?"
    
    rows, err := db.Query(query, minAge)
    if err != nil {
        return nil, fmt.Errorf("query failed: %w", err)
    }
    defer rows.Close()

    var users []User
    for rows.Next() {
        var u User
        if err := rows.Scan(&u.ID, &u.Name, &u.Age); err != nil {
            return nil, fmt.Errorf("scan failed: %w", err)
        }
        users = append(users, u)
    }

    if err := rows.Err(); err != nil {
        return nil, fmt.Errorf("rows iteration error: %w", err)
    }

    return users, nil
}

func main() {
    dsn := "user:password@tcp(database-server:3306)/database-name?parseTime=true"
    
    db, err := NewDatabase(dsn)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    users, err := db.GetUsersByMinAge(18)
    if err != nil {
        log.Fatal(err)
    }

    for _, user := range users {
        fmt.Printf("ID: %d, Name: %s, Age: %d\n", user.ID, user.Name, user.Age)
    }
}

主要改进点:

  1. 封装数据库操作到结构体方法中
  2. 添加连接池配置
  3. 使用结构体映射查询结果
  4. 更详细的错误包装
  5. 添加parseTime=true参数支持时间类型
回到顶部