Utilize o pacote database/sql do Go com instruções SQL do LindormTable para se conectar ao LindormTable e executar operações CRUD. Este guia aborda:
Adição da dependência do Go MySQL Driver
Configuração dos parâmetros de conexão e do pool de conexões
Criação de tabela, escrita, consulta e exclusão de dados
Execução da aplicação de exemplo completa e verificação dos resultados
Pré-requisitos
Antes de começar, certifique-se de ter:
Go 1.17 ou superior. Consulte Go para obter instruções de instalação.
Compatibilidade com MySQL ativada na sua instância Lindorm. Veja Enable the MySQL compatibility feature.
Endereço IP do seu cliente adicionado à lista de permissões da instância Lindorm. Consulte Configure whitelists.
Notas sobre conexão e confiabilidade
Os nós de frontend SQL do LindormTable utilizam o Server Load Balancer (SLB) para distribuir requisições de clientes entre os nós. Para manter uma distribuição equilibrada das conexões, evite tempos longos de keep-alive. Configure
SetConnMaxLifetimepara renovar as conexões periodicamente.Em ambientes de rede complexos — com alta latência, perda de pacotes ou instabilidade — as conexões podem ser interrompidas. Configure um pool de conexões adequado e adicione lógica de nova tentativa no código da sua aplicação.
Durante reinicializações do servidor para atualizações, as conexões podem cair temporariamente. Mesmo com um pool de conexões, sua aplicação pode encontrar exceções. Capture esses erros e tente novamente.
-
Ajuste as configurações do pool de conexões de acordo com seu tráfego. Poucas conexões causam enfileiramento de requisições e aumentam o tempo de resposta (RT). Imprima o status do pool para diagnosticar problemas de conexão:
fmt.Printf("%+v\n", db.Stats())
Conecte-se ao LindormTable
Etapa 1: Adicione a dependência do driver
No arquivo go.mod do seu projeto, adicione o Go MySQL Driver:
require github.com/go-sql-driver/mysql v1.7.1
Etapa 2: Configure os parâmetros de conexão
Defina as constantes de conexão:
const (
user = "<your-username>"
password = "<your-password>"
host = "<LindormTable-endpoint-for-MySQL>"
port = 33060
database = "default"
connectTimeout = "10s"
)
Referência de parâmetros
|
Parâmetro |
Descrição |
|
|
Nome de usuário para acesso ao LindormTable. Para redefinir a senha, consulte Manage users. |
|
|
Senha para acesso ao LindormTable. |
|
|
LindormTable Endpoint For MySQL. Consulte View endpoints. Para aplicações implantadas em ECS, use o endpoint de VPC para menor latência e maior segurança. Para acesso via internet, ative o endpoint público no console: Database Connections > Wide Table Engine > Enable Public Endpoint. |
|
|
Valor fixo: |
|
|
Nome do banco de dados. O padrão é |
|
|
Tempo limite de conexão. Unidade: segundos (s). |
Etapa 3: Abra uma conexão e configure o pool
Construa a URL de conexão e defina as configurações do pool antes de executar qualquer 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)
Trechos de código de exemplo
Todos os exemplos utilizam db.Exec, db.Query e db.Prepare do pacote padrão database/sql do Go.
Liste bancos de dados
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)
}
Crie uma tabela
_, 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
}
Escreva dados
Escrita direta
_, err = db.Exec("upsert into user_test(id,name,age) values(1,'zhangsan',17)")
if err != nil {
fmt.Println("insert data error", err)
return
}
Escrita parametrizada (recomendada para escritas repetidas — reutilize Stmt em cenários 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
}
Consulte dados
Consulta direta
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)
}
Exclua dados
_, err = db.Exec("delete from user_test where id=1")
if err != nil {
fmt.Println("delete data error", err)
return
}
Código de exemplo completo
A seguir, apresentamos um exemplo executável de ponta a ponta que se conecta ao LindormTable, cria uma tabela, escreve linhas, consulta-as e exclui uma delas.
Em produção, carregue credenciais a partir de variáveis de ambiente em vez de codificá-las diretamente no código-fonte.
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
}
}
}
Sempre chamerows.Close()após iterar sobre os resultados. Para cenários de alto throughput, reutilize objetosStmt. Ao usar APIs com suporte a contexto, comoQueryContexteExecContext, evite tempos limite muito curtos — pausas na coleta de lixo (GC) do cliente podem acionar timeouts de contexto e causar redefinições de conexão.
Verifique os resultados
Quando a instância contém apenas o banco de dados default, a saída é:
default
information_schema
id: 1 name: zhangsan age: 17
id: 2 name: lisi age: 18
id: 1 name: zhangsan age: 17
Essa saída confirma:
defaulteinformation_schema— existem dois bancos de dados na instância.id: 1 name: zhangsan age: 17eid: 2 name: lisi age: 18— ambas as linhas foram escritas com sucesso.id: 1 name: zhangsan age: 17— a consulta parametrizada (where id=?) retornou a linha comid=1.
Próximos passos
Manage users — altere senhas e gerencie acessos
View endpoints — localize endpoints de VPC e públicos
Configure whitelists — gerencie listas de permissões de IP