golang轻松操作rqlite数据库API的客户端插件go-rqlite的使用

Golang轻松操作rqlite数据库API的客户端插件go-rqlite使用指南

概述

gorqlite是一个用于rqlite的Go客户端,提供了易于使用的抽象层来操作rqlite API。它提供了专门为rqlite设计的惯用API,以及一个database/sql驱动。

主要特性

  • 抽象了rqlite HTTP API交互 - POST请求、JSON处理等
  • 提供类似database/sql的语义,如Open()Query()QueryOne()Next()/Scan()/Map()Write()WriteOne()
  • 支持rqlite特有的操作:Leader()Peers()检查集群、SetConsistencyLevel()更改一致性级别
  • 支持调试跟踪功能Trace(io.Writer)/Trace(nil)
  • 无外部依赖,仅使用标准库函数

安装

go get github.com/rqlite/gorqlite

使用示例

基本连接

// 连接到localhost:4001无认证
conn, err := gorqlite.Open("http://") 

// 使用HTTPS
conn, err := gorqlite.Open("https://") 

// 明确指定地址
conn, err := gorqlite.Open("https://localhost:4001/")

// 带认证的连接
conn, err := gorqlite.Open("https://mary:secret2@localhost:4001/")

// 设置一致性级别
conn, err := gorqlite.Open("https://server2.example.com:4001/?level=weak")

// 设置超时
conn, err := gorqlite.Open("https://localhost:2265/?level=strong&timeout=30")

// 禁用集群发现
conn, err := gorqlite.Open("https://localhost:2265/?disableClusterDiscovery=true")

自定义HTTP客户端

// 创建跳过证书验证的TLS传输
tn := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

// 创建HTTP客户端并传递给库
client := &http.Client{Transport: tn}
conn, err := gorqlite.OpenWithClient("https://localhost:4001/", client)

执行写入操作

// 模拟database/sql Prepare()
statements := make([]string, 0)
pattern := "INSERT INTO secret_agents(id, hero_name, abbrev) VALUES (%d, '%s', '%3s')"
statements = append(statements, fmt.Sprintf(pattern, 125718, "Speed Gibson", "Speed"))
statements = append(statements, fmt.Sprintf(pattern, 209166, "Clint Barlow", "Clint"))
statements = append(statements, fmt.Sprintf(pattern, 44107, "Barney Dunlap", "Barney"))
results, err := conn.Write(statements)

// 处理结果
for n, v := range results {
    fmt.Printf("结果%d影响了%d行\n", n, v.RowsAffected)
    if v.Err != nil {
        fmt.Printf("错误: %s\n", v.Err.Error())
    }
}

// 单条写入并获取最后插入ID
res, err := conn.WriteOne("INSERT INTO foo (name) values ('bar')")
fmt.Printf("最后插入ID: %d\n", res.LastInsertID)

执行查询操作

var id int64
var name string

// 查询单条语句
rows, err := conn.QueryOne("select id, name from secret_agents where id > 500")
fmt.Printf("查询返回%d行\n", rows.NumRows)

// 遍历结果
for rows.Next() {
    err := rows.Scan(&id, &name)
    fmt.Printf("这是第%d行\n", rows.RowNumber)
    fmt.Printf("总共有%d行\n", rows.NumRows)
}

// 使用Map()获取结果
for rows.Next() {
    m, err := rows.Map()
    // m现在是map[列名]interface{}
    id := m["id"].(float64) // JSON数字类型
    name := m["name"].(string)
}

参数化查询

// 参数化写入
wr, err := conn.WriteParameterized(
    []gorqlite.ParameterizedStatement{
        {
            Query:     "INSERT INTO secret_agents(id, name, secret) VALUES(?, ?, ?)",
            Arguments: []interface{}{7, "James Bond", "not-a-secret"},
        },
    },
)

// 参数化查询
qr, err := conn.QueryParameterized(
    []gorqlite.ParameterizedStatement{
        {
            Query:     "SELECT id, name from secret_agents where id > ?",
            Arguments: []interface{}{3},
        },
    },
)

集群信息

// 获取当前Leader
leader, err := conn.Leader()
fmt.Println("当前Leader:", leader)

// 获取所有Peer
peers, err := conn.Peers()
for n, p := range peers {
    fmt.Printf("集群Peer %d: %s\n", n, p)
}

调试跟踪

// 开启调试跟踪到文件
f, err := os.OpenFile("/tmp/deep_insights.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
gorqlite.TraceOn(f)

// 改为跟踪到标准错误
gorqlite.TraceOn(os.Stderr)

// 关闭跟踪
gorqlite.TraceOff()

database/sql驱动使用

package main

import (
    "database/sql"
    _ "github.com/rqlite/gorqlite/stdlib"
)

func main() {
    db, err := sql.Open("rqlite", "http://")
    if err != nil {
        panic(err)
    }
    _, err = db.Exec("CREATE TABLE users (id INTEGER, name TEXT)")
    if err != nil {
        panic(err)
    }
}

重要注意事项

  1. 如果使用访问控制,连接用户需要_status_权限
  2. rqlite不支持迭代获取,查询会将所有结果立即放入内存
  3. 在标准database/sql驱动中有一些限制:
    • 事务必须作为单个批处理提交
    • 不支持回滚
    • Prepare()是空操作

完整示例

package main

import (
    "fmt"
    "github.com/rqlite/gorqlite"
    "os"
)

func main() {
    // 1. 连接到rqlite
    conn, err := gorqlite.Open("http://localhost:4001")
    if err != nil {
        fmt.Printf("连接错误: %v\n", err)
        return
    }
    
    // 2. 创建表
    _, err = conn.WriteOne("CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT)")
    if err != nil {
        fmt.Printf("创建表错误: %v\n", err)
        return
    }
    
    // 3. 插入数据
    res, err := conn.WriteOne("INSERT INTO users (id, name) VALUES (1, 'Alice')")
    if err != nil {
        fmt.Printf("插入错误: %v\n", err)
        return
    }
    fmt.Printf("插入影响行数: %d\n", res.RowsAffected)
    
    // 4. 查询数据
    rows, err := conn.QueryOne("SELECT id, name FROM users")
    if err != nil {
        fmt.Printf("查询错误: %v\n", err)
        return
    }
    
    for rows.Next() {
        var id int64
        var name string
        err = rows.Scan(&id, &name)
        if err != nil {
            fmt.Printf("扫描错误: %v\n", err)
            continue
        }
        fmt.Printf("ID: %d, Name: %s\n", id, name)
    }
    
    // 5. 获取集群信息
    leader, err := conn.Leader()
    if err != nil {
        fmt.Printf("获取Leader错误: %v\n", err)
    } else {
        fmt.Printf("当前Leader: %s\n", leader)
    }
    
    peers, err := conn.Peers()
    if err != nil {
        fmt.Printf("获取Peers错误: %v\n", err)
    } else {
        fmt.Println("集群Peers:")
        for i, peer := range peers {
            fmt.Printf("  %d: %s\n", i, peer)
        }
    }
}

这个客户端库已被多个组织在生产环境中使用,包括Replicated。它提供了简单易用的API来操作rqlite数据库,适合需要高可用性SQLite解决方案的场景。


更多关于golang轻松操作rqlite数据库API的客户端插件go-rqlite的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang轻松操作rqlite数据库API的客户端插件go-rqlite的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-rqlite轻松操作rqlite数据库

rqlite是一个轻量级的分布式关系数据库,基于SQLite构建,提供了HTTP API接口。go-rqlite是rqlite的官方Go客户端库,让开发者可以方便地在Go应用中操作rqlite数据库。

安装go-rqlite

go get github.com/rqlite/go-rqlite

基本使用方法

1. 连接到rqlite服务器

package main

import (
	"fmt"
	"log"
	"github.com/rqlite/go-rqlite"
)

func main() {
	// 连接到本地rqlite服务器
	conn, err := rqlite.NewConnection("http://localhost:4001")
	if err != nil {
		log.Fatalf("连接失败: %v", err)
	}
	defer conn.Close()

	// 检查连接状态
	if err := conn.Ping(); err != nil {
		log.Fatalf("ping失败: %v", err)
	}
	fmt.Println("成功连接到rqlite服务器")
}

2. 执行SQL语句

// 创建表
func createTable(conn *rqlite.Connection) error {
	_, err := conn.Execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")
	return err
}

// 插入数据
func insertData(conn *rqlite.Connection) error {
	_, err := conn.Execute("INSERT INTO users(name, age) VALUES('Alice', 25), ('Bob', 30)")
	return err
}

3. 查询数据

func queryData(conn *rqlite.Connection) error {
	rows, err := conn.Query("SELECT * FROM users")
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var id, age int
		var name string
		if err := rows.Scan(&id, &name, &age); err != nil {
			return err
		}
		fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
	}
	return rows.Err()
}

高级功能

1. 事务处理

func transactionExample(conn *rqlite.Connection) error {
	tx, err := conn.Begin()
	if err != nil {
		return err
	}

	// 执行事务中的操作
	if _, err := tx.Execute("INSERT INTO users(name, age) VALUES('Charlie', 28)"); err != nil {
		tx.Rollback()
		return err
	}

	if _, err := tx.Execute("UPDATE users SET age = 26 WHERE name = 'Alice'"); err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit()
}

2. 批量操作

func batchExample(conn *rqlite.Connection) error {
	statements := []string{
		"INSERT INTO users(name, age) VALUES('David', 35)",
		"INSERT INTO users(name, age) VALUES('Eve', 22)",
		"DELETE FROM users WHERE age > 30",
	}

	_, err := conn.ExecuteBatch(statements)
	return err
}

3. 参数化查询

func parameterizedQuery(conn *rqlite.Connection) error {
	rows, err := conn.QueryParameterized(
		"SELECT * FROM users WHERE age > ?", 
		[]interface{}{25},
	)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var id, age int
		var name string
		if err := rows.Scan(&id, &name, &age); err != nil {
			return err
		}
		fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
	}
	return rows.Err()
}

完整示例

package main

import (
	"fmt"
	"log"
	"github.com/rqlite/go-rqlite"
)

func main() {
	// 1. 连接
	conn, err := rqlite.NewConnection("http://localhost:4001")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	// 2. 创建表
	if err := createTable(conn); err != nil {
		log.Fatal(err)
	}

	// 3. 插入数据
	if err := insertData(conn); err != nil {
		log.Fatal(err)
	}

	// 4. 查询数据
	fmt.Println("初始数据:")
	if err := queryData(conn); err != nil {
		log.Fatal(err)
	}

	// 5. 事务操作
	if err := transactionExample(conn); err != nil {
		log.Fatal(err)
	}

	// 6. 再次查询
	fmt.Println("\n事务后的数据:")
	if err := queryData(conn); err != nil {
		log.Fatal(err)
	}

	// 7. 参数化查询
	fmt.Println("\n年龄大于25的用户:")
	if err := parameterizedQuery(conn); err != nil {
		log.Fatal(err)
	}
}

// 其他函数定义同上...

注意事项

  1. rqlite默认使用强一致性模式,所有写操作都会等待leader节点确认
  2. 对于高并发场景,可以考虑使用连接池
  3. 生产环境建议配置多个节点实现高可用
  4. 大表查询可能会影响性能,建议添加适当的索引

go-rqlite提供了简单直观的API,让Go开发者可以轻松地与rqlite数据库交互,同时支持事务、批量操作等高级功能,非常适合需要SQLite功能但又要分布式特性的应用场景。

回到顶部