【问题标题】:MySQL's bit type maps to which Go type?MySQL 位类型映射到哪个 Go 类型?
【发布时间】:2018-05-12 03:27:57
【问题描述】:

我以前用过Java,所以数据库表中某些列的类型是bit(1)。但是现在我想使用beego来重建我的项目,我不想改变我的数据库表(需要做很多事情)。我在我的项目中使用beego的orm。那么我应该使用哪种 Go 类型呢?

这样的表和被删除的列有问题:

+--------------+--------------+------+-----+---------+-------+
| Field        | Type         | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id           | varchar(255) | NO   | PRI | NULL    |       |
| created_time | datetime     | YES  |     | NULL    |       |
| deleted      | bit(1)       | NO   |     | NULL    |       |
| updated_time | datetime     | YES  |     | NULL    |       |
| icon_class   | varchar(255) | YES  |     | NULL    |       |
| mark         | varchar(255) | YES  |     | NULL    |       |
| name         | varchar(255) | YES  |     | NULL    |       |
| parent       | varchar(255) | YES  |     | NULL    |       |
+--------------+--------------+------+-----+---------+-------+

这样的结构:

type BaseModel struct {
    Id          string           `orm:"pk";form:"id"`
    CreatedTime time.Time        `orm:"auto_now_add;type(datetime)";form:"-"`
    UpdatedTime time.Time        `orm:"auto_now;type(datetime)";form:"-"`
    Deleted     bool `form:"-"`
}

当我在代码中使用 bool 时,错误如下:

`[0]` convert to `*orm.BooleanField` failed, field: shareall-go/models.Category.BaseModel.Deleted err: strconv.ParseBool: parsing "\x00": invalid syntax

【问题讨论】:

  • 首先,如果您的类型对应于一个布尔值(看起来,基于名称),您应该在 MySQL 中使用BOOL。一旦您进行了更改,希望您的实际问题的答案将是显而易见的。
  • 但我想我不能改变类型。旧的 Java 程序现在正在运行。我不确定更改后旧程序能否正常运行。
  • 如果您需要使用该架构,那很糟糕,但请继续使用。但我的评论应该仍然有助于回答您的问题。
  • 好的,让我在测试条件下试一试。谢谢。

标签: mysql go orm beego


【解决方案1】:

那么我应该使用哪种 Go 类型?

通常,这取决于您使用数据的方式,而不是数据的存储方式。正如您所逃避的那样,您尝试将其用作Bool(这是有道理的)但出现错误。

问题在于 MySQL 表达 BITBOOL 不同,Go MySQL 驱动程序需要 MySQL BOOL。您可以通过使用实现sql.Scanner 接口的自定义类型来解决此问题。由于您大概只有两个(或者可能是三个,如果您算上NULL)输入,因此应该相当容易。请注意,此代码不完整且未经测试。它旨在作为指导,而不是复制粘贴解决方案。

type MyBool bool

func (b *MyBool) Scan(src interface{}) error {
    str, ok := src.(string)
    if !ok {
        return fmt.Errorf("Unexpected type for MyBool: %T", src)
    }
    switch str {
    case "\x00":
        v := false
        *b = v
    case "\x01":
        v := true
        *b = v
    }
    return nil
}

【讨论】:

    【解决方案2】:

    Sqlx 还为这种情况创建了一个自定义 bool 数据类型,它工作正常。 Link to related code

    // BitBool is an implementation of a bool for the MySQL type BIT(1).
    // This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT.
    type BitBool bool
    
    // Value implements the driver.Valuer interface,
    // and turns the BitBool into a bitfield (BIT(1)) for MySQL storage.
    func (b BitBool) Value() (driver.Value, error) {
        if b {
            return []byte{1}, nil
        } else {
            return []byte{0}, nil
        }
    }
    
    // Scan implements the sql.Scanner interface,
    // and turns the bitfield incoming from MySQL into a BitBool
    func (b *BitBool) Scan(src interface{}) error {
        v, ok := src.([]byte)
        if !ok {
            return errors.New("bad []byte type assertion")
        }
        *b = v[0] == 1
        return nil
    }
    

    【讨论】:

    • 扫描函数可以如下使用; var valOrg interface{} var valBB types.BitBool var val bool .... err = query.Scan(..., &valOrg,...) .... err = valBB.Scan(valOrg) val = bool(valBB )
    【解决方案3】:

    我不知道为什么 Tarmo 的解决方案对我不起作用。但稍作修改后,它就可以工作了。

    type BitBool bool
    
    func (bb BitBool) Value() (driver.Value, error) {
        return bool(bb), nil
    }
    
    func (bb *BitBool) Scan(src interface{}) error {
        if src == nil {
            // MySql NULL value turns into false
            *bb = false
            return nil
        }
        bs, ok := src.([]byte)
        if !ok {
            return fmt.Errorf("Not byte slice!")
        }
        *bb = bs[0] == 1
        return nil
    }
    

    这样,我可以做到以下几点

    var isVip BitBool
    row := db.QueryRow("SELECT is_vip FROM user WHERE user_id = '12345'")
    err := row.Scan(&isVip)
    
    var isVip BitBool = true
    rows, err := db.Query("SELECT username FROM user WHERE is_vip = ?", isVip)
    

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2015-02-06
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多