golang操作MySQL几个原则和示例

董泽润 · · 2107 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

使用原则

  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
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:董泽润

查看原文:golang操作MySQL几个原则和示例

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2107 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传