golang操作MySQL几个原则和示例

2017-01-22  本文已影响685人  董泽润

使用原则

  1. 库自带连接池,使用方不需自行实现。*sql.DB 线程安全,开箱即用,屏弊了底层创建连接的实现
  2. Open 只是创建类,调用一次即可,使用前需要 Ping 确保连接正常。
  3. 一定要设置连接池的两个参数 MaxIdle, MaxOpen,否则在极端情况会把 DB 连接打满(未加索引,大事务阻塞)。可选 MaxLifetime,需咨询 DBA,一般 DB 默认8小时,无需设置,如果很短要视情况而定
  4. 事务会占用一个连接,尽可能减小事务耗时,打散大事务,否则会将 DB 连接数打满
  5. prepare 会占用一个连接,每次使用完后,一定要 close ,否则同样会将连接数打满
  6. DSN 需要指定时区和对时间字段的支持,否则会出现时间提前8小时的问题
  7. Query, Prepare, Exec 无需业务层重试,底层已经实现

下一篇源码走读会详细说明原因

连接创建示例

type MySQLClient struct {
    Host    string
    MaxIdle int
    MaxOpen int
    User    string
    Pwd     string
    DB      string
    Port    int
    pool    *sql.DB
}

func (mc *MySQLClient) Init() (err error) {
    // 构建 DSN 时尤其注意 loc 和 parseTime 正确设置
    // 东八区,允许解析时间字段
    uri := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&loc=%s&parseTime=true",
        mc.User,
        mc.Pwd,
        mc.Host,
        mc.Port,
        mc.DB,
        url.QueryEscape("Asia/Shanghai"))
    // Open 全局一个实例只需调用一次
    mc.pool, err = sql.Open("mysql", uri)
    if err != nil {
        return err
    }
    //使用前 Ping, 确保 DB 连接正常
    err = mc.pool.Ping()
    if err != nil {
        return err
    }
    // 设置最大连接数,一定要设置 MaxOpen
    mc.pool.SetMaxIdleConns(mc.MaxIdle)
    mc.pool.SetMaxOpenConns(mc.MaxOpen)
    return nil
}

数据库查询示例

func testQuery(beginTime, endTime, code string) ([]*OrderInfo, error) {
    db := iowrapper.MySQLClient.GetMySQL()
    err := db.Ping()
    if err != nil {
        return nil, err
    }

    var rows *sql.Rows
    // sql 可以用占位符,涉及业务分表提前生成
    rows, err = db.Query(getSqlByCode(code, beginTime, endTime))
    if err != nil {
        return nil, err
    }

    OrderInfos := make([]*OrderInfo, 0, 10)

    for rows.Next() {
        oi := &OrderInfo{}
        var createTime time.Time

        err := rows.Scan(&oi.OrderId, &createTime, &oi.StartingLng, &oi.StartingLat, &oi.DestLng, &oi.DestLat)
        if err != nil {
            continue
        }

        oi.CreateTime = createTime.Unix()
        OrderInfos = append(OrderInfos, oi)
    }

    return OrderInfos, nil
}

数据库更新示例

func testExec() error {
    sql := "update test.table1 set _create_time=now() where id=?"
    res, err := db.Exec(sql, 7988161482)
    if err != nil {
        fmt.Println("exec error ", err.Error())
        return err
    }
    fmt.Println(res.LastInsertId())
    fmt.Println(res.RowsAffected())
    return nil
}

数据库prepare示例

func testStmt() error {
    //占位符sql
    sql := "update test.table1 set _create_time=now() where id=?"
    stmt, err := db.Prepare(sql)
    if err != nil {
        fmt.Println("stmt error ", err.Error())
        return err
    }
    // 一定要关闭,很重要
    defer stmt.Close()

    // 可以批量,示例只有一个
    _, err = stmt.Exec(7988161474)
    if err != nil {
        fmt.Println("stmt exec error ", err.Error())
        return err
    }
    return nil
}
上一篇下一篇

猜你喜欢

热点阅读