Golang中如何将MySQL的tinyint类型保存到数据表

Golang中如何将MySQL的tinyint类型保存到数据表 我有一个MySQL字段,其类型为tinyint,而Go结构体中的对应字段是布尔类型。

保存时报告未能成功保存。

应如何处理此问题

4 回复

如果我拥有十万条记录。我的循环是不必要的

更多关于Golang中如何将MySQL的tinyint类型保存到数据表的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你需要将布尔值映射为整数,例如:

type User struct {
    Username string
    Email string
    Acitve bool
}

u := new(User)
var active int

stmt.QueryRow(email).Scan(&u.Username, &u.Email, &active)

if active == 0 {
    u.Active = false
} else {
    u.Active = true
}

可以尝试使用 ent

这是一个示例结构体

package schema

import (
	"entgo.io/ent"
	"entgo.io/ent/dialect/entsql"
	"entgo.io/ent/schema"
	"entgo.io/ent/schema/field"
)

type Demo struct {
	ent.Schema
}

func (Demo) Fields() []ent.Field {
	return []ent.Field{
		field.Uint64("id").Unique(),
		field.String("name"),
		field.Bool("is_delete"),
	}
}

func (Demo) Edges() []ent.Edge {
	return []ent.Edge{}
}

func (DhExpert) Demo() []schema.Annotation {
	return []schema.Annotation{entsql.Annotation{Table: "demo"}}
}

可以像这样进行 Create 操作:

	sdn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", "root", "123456", "192.168.1.203", 3306, "ent_test")

	client, err := ent.Open("mysql", sdn)
	if err != nil {
		log.Fatalf("failed opening connection to sqlite: %v", err)
	}
	defer client.Close()
	ctx := context.Background()

	// Run the auto migration tool.
	if err := client.Schema.Create(ctx); err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	}
      // create 
	cli.Debug().Demo.Create().SetID(1).SetName("xx").SetIsDelete(false).SaveX(ctx)

    // query
	xx, _ := client.Demo.Query().All(context.Background())
	for _, v := range xx {
		fmt.Printf("%v\n", v)
	}

在Golang中处理MySQL的tinyint(1)与bool类型的映射,需要使用sql.NullBool类型或实现database/sqlScannerValuer接口。以下是具体解决方案:

方案一:使用sql.NullBool(推荐)

import (
    "database/sql"
    "fmt"
)

type User struct {
    ID    int64
    Name  string
    // 使用sql.NullBool替代bool
    Active sql.NullBool
}

// 插入数据示例
func createUser(db *sql.DB, user *User) error {
    _, err := db.Exec(
        "INSERT INTO users (name, active) VALUES (?, ?)",
        user.Name,
        user.Active,
    )
    return err
}

// 查询数据示例
func getUser(db *sql.DB, id int64) (*User, error) {
    var user User
    err := db.QueryRow(
        "SELECT id, name, active FROM users WHERE id = ?",
        id,
    ).Scan(&user.ID, &user.Name, &user.Active)
    
    if err != nil {
        return nil, err
    }
    return &user, nil
}

// 使用示例
func main() {
    user := &User{
        Name: "John Doe",
        Active: sql.NullBool{
            Bool:  true,
            Valid: true, // 设置为true表示该字段有效
        },
    }
    
    // 检查布尔值
    if user.Active.Valid && user.Active.Bool {
        fmt.Println("User is active")
    }
}

方案二:自定义类型实现Scanner和Valuer接口

import (
    "database/sql"
    "database/sql/driver"
    "fmt"
)

// 自定义Bool类型
type Bool bool

// Scan实现Scanner接口
func (b *Bool) Scan(value interface{}) error {
    if value == nil {
        *b = false
        return nil
    }
    
    switch v := value.(type) {
    case int64:
        *b = v != 0
    case bool:
        *b = Bool(v)
    default:
        return fmt.Errorf("unsupported type: %T", value)
    }
    return nil
}

// Value实现Valuer接口
func (b Bool) Value() (driver.Value, error) {
    return bool(b), nil
}

type Product struct {
    ID     int64
    Name   string
    // 使用自定义Bool类型
    InStock Bool
}

// 使用示例
func handleProduct(db *sql.DB) error {
    // 插入
    product := &Product{
        Name:    "Laptop",
        InStock: true,
    }
    
    _, err := db.Exec(
        "INSERT INTO products (name, in_stock) VALUES (?, ?)",
        product.Name,
        product.InStock, // 自动调用Value()方法
    )
    if err != nil {
        return err
    }
    
    // 查询
    var p Product
    err = db.QueryRow(
        "SELECT id, name, in_stock FROM products WHERE name = ?",
        "Laptop",
    ).Scan(&p.ID, &p.Name, &p.InStock) // 自动调用Scan()方法
    
    if err != nil {
        return err
    }
    
    fmt.Printf("Product in stock: %v\n", bool(p.InStock))
    return nil
}

方案三:使用GORM ORM

如果使用GORM,它会自动处理这种映射:

import (
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

type Customer struct {
    gorm.Model
    Name   string
    Active bool `gorm:"type:tinyint(1)"`
}

func main() {
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }
    
    // 自动迁移
    db.AutoMigrate(&Customer{})
    
    // 创建记录
    customer := Customer{
        Name:   "Alice",
        Active: true,
    }
    db.Create(&customer)
    
    // 查询
    var result Customer
    db.First(&result, "name = ?", "Alice")
    fmt.Printf("Customer active status: %v\n", result.Active)
}

直接使用database/sql的原始查询

// 对于简单的查询,可以直接使用int类型接收
type SimpleUser struct {
    ID     int64
    Name   string
    Active int // 使用int类型接收tinyint
}

func getSimpleUser(db *sql.DB, id int64) (*SimpleUser, error) {
    var user SimpleUser
    err := db.QueryRow(
        "SELECT id, name, active FROM users WHERE id = ?",
        id,
    ).Scan(&user.ID, &user.Name, &user.Active)
    
    if err != nil {
        return nil, err
    }
    
    // 手动转换
    isActive := user.Active == 1
    fmt.Printf("Is active: %v\n", isActive)
    
    return &user, nil
}

选择哪种方案取决于具体需求:

  • 需要处理NULL值:使用sql.NullBool
  • 需要类型安全且简洁:使用自定义类型实现接口
  • 使用ORM:GORM会自动处理
  • 简单场景:直接使用int类型接收并手动转换
回到顶部