Todos los productos
Search
Centro de documentos

Lindorm:Uso de Go para desarrollar aplicaciones

Última actualización: Sep 05, 2026

Utilice el paquete database/sql de Go junto con sentencias SQL de LindormTable para conectarse a LindormTable y ejecutar operaciones CRUD. Esta guía le muestra cómo:

  • Agregar la dependencia del controlador MySQL para Go

  • Configurar los parámetros de conexión y los ajustes del pool de conexiones

  • Crear una tabla, escribir, consultar y eliminar datos

  • Ejecutar la aplicación de ejemplo completa y comprobar los resultados

Requisitos previos

Antes de empezar, asegúrese de contar con lo siguiente:

  • Go 1.17 o posterior. Consulte Go para obtener las instrucciones de instalación.

  • La compatibilidad con MySQL habilitada en su instancia de Lindorm. Consulte Enable the MySQL compatibility feature.

  • La dirección IP de su cliente agregada a la lista de permitidos de la instancia de Lindorm. Consulte Configure whitelists.

Notas sobre conexión y confiabilidad

  • Los nodos frontend SQL de LindormTable utilizan Server Load Balancer (SLB) para distribuir las solicitudes de los clientes entre dichos nodos. Para mantener una distribución equilibrada de las conexiones, evite tiempos de keep-alive prolongados. Configure SetConnMaxLifetime para renovar las conexiones periódicamente.

  • En entornos de red complejos, con alta latencia, pérdida de paquetes o inestabilidad, las conexiones pueden interrumpirse. Configure un pool de conexiones adecuado e implemente lógica de reintentos en el código de su aplicación.

  • Durante los reinicios del servidor por actualizaciones, las conexiones pueden cerrarse temporalmente. Incluso con un pool de conexiones, su aplicación podría experimentar excepciones; capture estos errores y reintente la operación.

  • Ajuste la configuración del pool de conexiones según su tráfico. Un número insuficiente de conexiones provoca que las solicitudes se acumulen en la cola y aumente el tiempo de respuesta (RT). Imprima el estado del pool para diagnosticar problemas de conexión:

    fmt.Printf("%+v\n", db.Stats())

Conexión a LindormTable

Paso 1: Agregar la dependencia del controlador

En el archivo go.mod de su proyecto, agregue el controlador MySQL para Go:

require github.com/go-sql-driver/mysql v1.7.1

Paso 2: Configurar los parámetros de conexión

Establezca las constantes de conexión:

const (
    user           = "<your-username>"
    password       = "<your-password>"
    host           = "<LindormTable-endpoint-for-MySQL>"
    port           = 33060
    database       = "default"
    connectTimeout = "10s"
)

Referencia de parámetros

Parámetro

Descripción

user

Nombre de usuario para acceder a LindormTable. Para restablecer la contraseña, consulte Manage users.

password

Contraseña para acceder a LindormTable.

host

LindormTable Endpoint For MySQL. Consulte View endpoints. Para aplicaciones desplegadas en ECS, utilice el endpoint de VPC para obtener menor latencia y mayor seguridad. Para acceso desde Internet, habilite el endpoint público en la consola: Database Connections > Wide Table Engine > Enable Public Endpoint.

port

Valor fijo: 33060.

database

Nombre de la base de datos. El valor predeterminado es default.

connectTimeout

Tiempo de espera de conexión. Unidad: segundos (s).

Paso 3: Abrir una conexión y configurar el pool

Construya la URL de conexión y configure los ajustes del pool antes de ejecutar cualquier consulta:

url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?timeout=%s",
    user, password, host, port, database, connectTimeout)

db, err := sql.Open("mysql", url)
if err != nil {
    panic(err.Error())
}
defer db.Close()

// Maximum number of open connections. Default: 0 (unlimited).
// Set this to avoid waiting when connections are exhausted.
db.SetMaxOpenConns(20)

// Maximum number of idle connections. Default: 2.
// Set equal to SetMaxOpenConns to avoid unnecessary connection churn.
db.SetMaxIdleConns(20)

// Maximum idle time before a connection is closed. Default: 0 (no limit).
// 8 minutes is a safe default to reclaim stale idle connections.
db.SetConnMaxIdleTime(8 * time.Minute)

// Maximum connection lifetime. Rotate connections to avoid imbalance
// caused by long-lived persistent connections. 30 minutes recommended.
db.SetConnMaxLifetime(30 * time.Minute)

Fragmentos de código de ejemplo

Todos los ejemplos utilizan db.Exec, db.Query y db.Prepare del paquete estándar database/sql de Go.

Listar bases de datos

rows, err := db.Query("show databases")
if err != nil {
    panic(err.Error())
}
defer rows.Close()

for rows.Next() {
    var dbName string
    if err := rows.Scan(&dbName); err != nil {
        panic(err.Error())
    }
    fmt.Println(dbName)
}

Crear una tabla

_, 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
}

Escribir datos

Escritura directa

_, err = db.Exec("upsert into user_test(id,name,age) values(1,'zhangsan',17)")
if err != nil {
    fmt.Println("insert data error", err)
    return
}

Escritura parametrizada (recomendada para escrituras repetidas; reutilice Stmt en escenarios de alto throughput)

stmt, err := db.Prepare("upsert into user_test(id,name,age) values(?,?,?)")
if err != nil {
    fmt.Println("prepare error", err)
    return
}
defer stmt.Close()

_, err = stmt.Exec(2, "lisi", 18)
if err != nil {
    fmt.Println("upsert error", err)
    return
}

Consultar datos

Consulta directa

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() {
    if err = rows.Scan(&id, &name, &age); err != nil {
        fmt.Println("scan data error", err)
        return
    }
    fmt.Println("id:", id, "name:", name, "age:", age)
}

Consulta parametrizada

stmt, err := db.Prepare("select * from user_test where id=?")
if err != nil {
    fmt.Println("prepare error", err)
    return
}
defer stmt.Close()

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() {
    if err = rows.Scan(&id, &name, &age); err != nil {
        fmt.Println("scan data error", err)
        return
    }
    fmt.Println("id:", id, "name:", name, "age:", age)
}

Eliminar datos

_, err = db.Exec("delete from user_test where id=1")
if err != nil {
    fmt.Println("delete data error", err)
    return
}

Código de ejemplo completo

A continuación se presenta un ejemplo funcional de extremo a extremo que se conecta a LindormTable, crea una tabla, escribe filas, las consulta y elimina una de ellas.

En entornos de producción, cargue las credenciales desde variables de entorno en lugar de incluirlas directamente en el código fuente.
package main

import (
    "database/sql"
    "fmt"
    "time"
    _ "github.com/go-sql-driver/mysql"
)

const (
    // Set user to the username used to access LindormTable
    user = "user"
    // Set password to the password used to access LindormTable
    password = "test"
    // Set host to the LindormTable endpoint for MySQL
    host = "ld-uf6k8yqb741t3****-proxy-sql-lindorm-public.lindorm.rds.aliyuncs.com"
    // Port is fixed to 33060
    port = 33060
    // Set database to the name of the database to connect to
    database = "default"
    // Connection timeout
    connectTimeout = "20s"
)

func main() {
    // Build the connection URL and open the connection
    url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?timeout=%s",
        user, password, host, port, database, connectTimeout)
    db, err := sql.Open("mysql", url)
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()

    // Configure connection pool
    db.SetMaxOpenConns(20)
    db.SetMaxIdleConns(20)
    db.SetConnMaxIdleTime(8 * time.Minute)
    db.SetConnMaxLifetime(30 * time.Minute)

    // Print pool status every 10 seconds for diagnostics
    go func() {
        for {
            fmt.Printf("%+v\n", db.Stats())
            time.Sleep(10 * time.Second)
        }
    }()

    // List databases
    {
        rows, err := db.Query("show databases")
        if err != nil {
            panic(err.Error())
        }
        defer rows.Close()
        for rows.Next() {
            var dbName string
            if err := rows.Scan(&dbName); err != nil {
                panic(err.Error())
            }
            fmt.Println(dbName)
        }
    }

    // Create a table
    {
        _, 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
        }
    }

    // Write data — method 1: direct write
    {
        _, err = db.Exec("upsert into user_test(id,name,age) values(1,'zhangsan',17)")
        if err != nil {
            fmt.Println("insert data error", err)
            return
        }
    }

    // Write data — method 2: parameterized write
    {
        stmt, err := db.Prepare("upsert into user_test(id,name,age) values(?,?,?)")
        if err != nil {
            fmt.Println("prepare error", err)
            return
        }
        defer stmt.Close()
        _, err = stmt.Exec(2, "lisi", 18)
        if err != nil {
            fmt.Println("upsert error", err)
            return
        }
    }

    // Query data — method 1: direct query
    {
        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() {
            if err = rows.Scan(&id, &name, &age); err != nil {
                fmt.Println("scan data error", err)
                return
            }
            fmt.Println("id:", id, "name:", name, "age:", age)
        }
    }

    // Query data — method 2: parameterized query
    {
        stmt, err := db.Prepare("select * from user_test where id=?")
        if err != nil {
            fmt.Println("prepare error", err)
            return
        }
        defer stmt.Close()
        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() {
            if err = rows.Scan(&id, &name, &age); err != nil {
                fmt.Println("scan data error", err)
                return
            }
            fmt.Println("id:", id, "name:", name, "age:", age)
        }
    }

    // Delete data
    {
        _, err = db.Exec("delete from user_test where id=1")
        if err != nil {
            fmt.Println("delete data error", err)
            return
        }
    }
}
Llame siempre a rows.Close() después de iterar sobre los resultados. En escenarios de alto throughput, reutilice los objetos Stmt. Al usar API con soporte de contexto, como QueryContext y ExecContext , evite tiempos de espera muy cortos, ya que las pausas del recolector de basura (GC) del cliente pueden activar tiempos de espera de contexto y provocar el restablecimiento de conexiones.

Comprobar los resultados

Cuando la instancia contiene únicamente la base de datos default, la salida es la siguiente:

default
information_schema
id: 1 name: zhangsan age: 17
id: 2 name: lisi age: 18
id: 1 name: zhangsan age: 17

Esta salida confirma lo siguiente:

  • default y information_schema indican que existen dos bases de datos en la instancia.

  • id: 1 name: zhangsan age: 17 y id: 2 name: lisi age: 18 confirman que ambas filas se escribieron correctamente.

  • id: 1 name: zhangsan age: 17 muestra que la consulta parametrizada (where id=?) devolvió la fila con id=1.

Pasos siguientes