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
SetConnMaxLifetimepara 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 |
|
|
Nombre de usuario para acceder a LindormTable. Para restablecer la contraseña, consulte Manage users. |
|
|
Contraseña para acceder a LindormTable. |
|
|
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. |
|
|
Valor fijo: |
|
|
Nombre de la base de datos. El valor predeterminado es |
|
|
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 arows.Close()después de iterar sobre los resultados. En escenarios de alto throughput, reutilice los objetosStmt. Al usar API con soporte de contexto, comoQueryContextyExecContext, 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:
defaultyinformation_schemaindican que existen dos bases de datos en la instancia.id: 1 name: zhangsan age: 17yid: 2 name: lisi age: 18confirman que ambas filas se escribieron correctamente.id: 1 name: zhangsan age: 17muestra que la consulta parametrizada (where id=?) devolvió la fila conid=1.
Pasos siguientes
Manage users: cambie contraseñas y gestione el acceso.
View endpoints: localice los endpoints de VPC y públicos.
Configure whitelists: gestione las listas de IP permitidas.