基于Go database/sql接口的应用开发

本文介绍通过Go语言的database/sql包使用SQL开发Lindorm宽表应用的方法和示例。

前提条件

  • 已下载并安装Go环境,建议安装Go 1.17及以上版本。

  • 已将客户端IP地址添加至Lindorm实例的白名单中,具体操作,请参见设置白名单

使用限制

本文操作仅适用于Lindorm宽表模式,不支持Lindorm宽表Serverless模式。

操作步骤

  1. 在Go项目程序的go.mod文件中添加以下依赖:

    require github.com/apache/calcite-avatica-go/v5 v5.0.0
    replace github.com/apache/calcite-avatica-go/v5 => github.com/aliyun/alibabacloud-lindorm-go-sql-driver/v5 v5.0.6
  2. .go文件中添加数据库驱动的依赖,内容如下:

    import (
        avatica "github.com/apache/calcite-avatica-go/v5"
    )
  3. .go文件的main方法中初始化连接池并配置以下参数,示例如下:

    databaseUrl := "http://localhost:30060" 
    
    conn := avatica.NewConnector(databaseUrl).(*avatica.Connector)
    conn.Info = map[string]string{
        "user":     "sql",     
        "password": "test",   
        "database": "default", 
    }
    db := sql.OpenDB(conn)
    // 设置连接池参数
    db.SetConnMaxIdleTime(8 * time.Minute)
    db.SetMaxOpenConns(20)
    db.SetMaxIdleConns(2)

    参数说明如下:

    参数

    是否必选

    说明

    databaseUrl

    Lindorm宽表SQL地址,例如:http://ld-bp12pc23yfb38****-proxy-lindorm.lindorm.rds.aliyuncs.com:30060。查看方法请参见查看宽表引擎连接地址

    user

    访问宽表引擎的用户名。

    password

    访问宽表引擎的密码,如果您忘记了密码,可以通过Lindorm宽表引擎的集群管理系统修改密码,具体请参见修改用户密码

    database

    数据库名。

    SetConnMaxIdleTime

    设置最大空闲时间。默认值为0,表示不超时。

    SetMaxOpenConns

    设置连接池中允许的最大连接数。默认值为0,表示没有限制。

    SetMaxIdleConns

    设置连接池中允许的最大空闲连接数。默认值为2。

  4. 在宽表引擎中进行创建表、写入数据、查询数据、删除数据操作,示例如下:

    • 创建表

      _, err := db.Exec("create table if not exists user_test(id int, name varchar,age int, primary key(id))")
      if err != nil {
          fmt.Println("create table error ", err)
          return
      }
    • 写入数据

      • 方法一:直接写入数据。

        _, err = db.Exec("upsert into user_test(id,name,age) values(1,'zhangsan',17)")
        if err != nil {
            fmt.Println("insert data error", err)
            return
        }
      • 方法二:通过绑定参数的方式进行写入数据。

        stmt, err := db.Prepare("upsert into user_test(id,name,age) values(?,?,?)")
        if err != nil {
            fmt.Println("prepare error", err)
            return
        }
        _, err = stmt.Exec(1, "zhangsan", 17)
        if err != nil {
            fmt.Println("upsert error", err)
            return
        }
    • 查询数据

      • 方法一:直接查询数据。

        rows, err := db.Query("select * from user_test")
        if err != nil {
            fmt.Println("query data error", err)
            return
        }
        defer rows.Close()
        var id int
        var name string
        var age int
        for rows.Next() {
            err = rows.Scan(&id, &name, &age)
            if err != nil {
                   fmt.Println("scan data error", err)
                return
            }
            fmt.Println("id:", id, "name:", name, "age:", age)
        }
      • 方法二:通过绑定参数的方式执行参数化查询。

        stmt, err = db.Prepare("select * from user_test where id=?")
        if err != nil {
            fmt.Println("prepare error", err)
            return
        }
        rows, err := stmt.Query(1)
        if err != nil {
            fmt.Println("query data error", err)
            return
        }
        defer rows.Close()
        var id int
        var name string
        var age int
        for rows.Next() {
            err = rows.Scan(&id, &name, &age)
            if err != nil {
                   fmt.Println("scan data error", err)
                return
            }
            fmt.Println("id:", id, "name:", name, "age:", age)
        }
    • 删除数据

      _, err = db.Exec("delete from user_test where id=1")
      if err != nil {
          fmt.Println("delete data error", err)
          return
      }
    说明
    • 在业务应用的实现中,对于写入或查询语句相对固化的场景,推荐使用上述绑定参数的方式,使用Prepare之后的stmt对象执行写入或查询。因为这种方式对于相同的语句只会执行一次SQL的解析、改写、优化逻辑,有助于提升执行性能。

    • 完整的示例代码请参见代码示例通过绑定参数写入和查询数据