golang简单强大的SQL数据库操作插件库KSQL的使用

Golang简单强大的SQL数据库操作插件库KSQL的使用

KSQL是一个为Golang设计的简单而强大的SQL数据库操作库,旨在提供易于使用且功能丰富的API来与SQL数据库交互。

主要特点

  • 每个操作只返回一次错误,便于错误处理
  • 提供日常操作的辅助函数:Insert、Patch和Delete
  • 通用且强大的查询和扫描数据到结构体的功能
  • 基于成熟的库如database/sqlpgx构建
  • 支持sql.Scannersql.Valuer接口
  • 支持pgx的特殊类型(使用kpgx时)

快速入门示例

package main

import (
	"context"
	"errors"
	"fmt"
	"log"

	"github.com/vingarcia/ksql"
	"github.com/vingarcia/ksql/adapters/kpgx"
)

var UsersTable = ksql.NewTable("users", "user_id")

type User struct {
	ID    int    `ksql:"user_id"`
	Name  string `ksql:"name"`
	Type  string `ksql:"type"`
	Posts []Post
}

// Post与User是多对一关系
var PostsTable = ksql.NewTable("posts", "post_id")

type Post struct {
	ID     int    `ksql:"post_id"`
	UserID int    `ksql:"user_id"`
	Title  string `ksql:"title"`
	Text   string `ksql:"text"`
}

// Address与User是一对一关系
var AddressesTable = ksql.NewTable("addresses", "id")

type Address struct {
	ID       int    `ksql:"id"`
	UserID   int    `ksql:"user_id"`
	FullAddr string `ksql:"full_addr"`
}

func main() {
	ctx := context.Background()
	dbURL, closeDB := startExampleDB(ctx)
	defer closeDB()

	db, err := kpgx.New(ctx, dbURL, ksql.Config{})
	if err != nil {
		log.Fatalf("unable connect to database: %s", err)
	}
	defer db.Close()

	// 查询部分属性可以使用自定义结构体
	var count []struct {
		Count int    `ksql:"count"`
		Type  string `ksql:"type"`
	}
	err = db.Query(ctx, &count, "SELECT type, count(*) as count FROM users GROUP BY type")
	if err != nil {
		log.Fatalf("unable to query users: %s", err)
	}

	fmt.Println("number of users by type:", count)

	// 从数据库加载实体时,如果省略SELECT部分,KSQL会自动构建
	var adminUsers []User
	err = db.Query(ctx, &adminUsers, "FROM users WHERE type = $1", "admin")
	if err != nil {
		log.Fatalf("unable to query admin users: %s", err)
	}

	fmt.Println("admin users:", adminUsers)

	// 加载用户及其帖子的好方法
	var user User
	err = errors.Join(
		db.QueryOne(ctx, &user, "FROM users WHERE user_id = $1", 42),
		db.Query(ctx, &user.Posts, "FROM posts WHERE user_id = $1", user.ID),
	)
	if err != nil {
		log.Fatalf("unable to query users: %s", err)
	}

	fmt.Println("user with posts:", user)

	// 从连接表中检索数据
	var rows []struct {
		OneUser    User    `tablename:"users"`
		OneAddress Address `tablename:"addr"`
	}
	err = db.Query(ctx, &rows,
		`FROM users
		JOIN addresses addr
		  ON users.user_id = addr.user_id`,
	)
	if err != nil {
		log.Fatalf("unable to query users: %s", err)
	}

	fmt.Println("rows of joined tables:", rows)
}

CRUD操作示例

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/vingarcia/ksql"
	"github.com/vingarcia/ksql/adapters/ksqlite3"
	"github.com/vingarcia/ksql/nullable"
)

type User struct {
	ID   int    `ksql:"id"`
	Name string `ksql:"name"`
	Age  int    `ksql:"age"`

	// json修饰符会将地址以JSON格式保存到数据库
	Address Address `ksql:"address,json"`

	// timeNowUTC修饰符会在保存前将此字段设置为time.Now().UTC()
	UpdatedAt time.Time `ksql:"updated_at,timeNowUTC"`

	// timeNowUTC/skipUpdates修饰符只在首次创建时设置此字段为time.Now().UTC()
	// 在更新时忽略它
	CreatedAt time.Time `ksql:"created_at,timeNowUTC/skipUpdates"`
}

type PartialUpdateUser struct {
	ID      int      `ksql:"id"`
	Name    *string  `ksql:"name"`
	Age     *int     `ksql:"age"`
	Address *Address `ksql:"address,json"`
}

type Address struct {
	State string `json:"state"`
	City  string `json:"city"`
}

// UsersTable告诉KSQL表名和主键列名默认为"id"
var UsersTable = ksql.NewTable("users")

func main() {
	ctx := context.Background()

	// 使用sqlite3
	db, err := ksqlite3.New(ctx, "/tmp/hello.sqlite", ksql.Config{
		MaxOpenConns: 1,
	})
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	// 创建表
	_, err = db.Exec(ctx, `CREATE TABLE IF NOT EXISTS users (
	  id INTEGER PRIMARY KEY,
		age INTEGER,
		name TEXT,
		address BLOB,
		created_at DATETIME,
		updated_at DATETIME
	)`)
	if err != nil {
		panic(err.Error())
	}

	// 插入记录
	var alison = User{
		Name: "Alison",
		Age:  22,
		Address: Address{
			State: "MG",
		},
	}
	err = db.Insert(ctx, UsersTable, &alison)
	if err != nil {
		panic(err.Error())
	}
	fmt.Println("Alison ID:", alison.ID)

	// 删除记录
	err = db.Delete(ctx, UsersTable, alison.ID)
	if err != nil {
		panic(err.Error())
	}

	// 查询单条记录
	var cris User
	err = db.QueryOne(ctx, &cris, "FROM users WHERE name = ? ORDER BY id", "Cristina")
	if err != nil {
		panic(err.Error())
	}

	// 更新记录
	cris.Name = "Cris"
	err = db.Patch(ctx, UsersTable, cris)

	// 部分更新技术1
	err = db.Patch(ctx, UsersTable, struct {
		ID  int `ksql:"id"`
		Age int `ksql:"age"`
	}{ID: cris.ID, Age: 28})
	if err != nil {
		panic(err.Error())
	}

	// 部分更新技术2
	err = db.Patch(ctx, UsersTable, PartialUpdateUser{
		ID:  cris.ID,
		Age: nullable.Int(28), // 只是一个int指针,如果为null则不会更新
	})
	if err != nil {
		panic(err.Error())
	}

	// 查询多条记录
	var users []User
	err = db.Query(ctx, &users, "FROM users LIMIT 10")
	if err != nil {
		panic(err.Error())
	}

	// 事务处理
	err = db.Transaction(ctx, func(db ksql.Provider) error {
		var cris2 User
		err = db.QueryOne(ctx, &cris2, "FROM users WHERE id = ?", cris.ID)
		if err != nil {
			return err
		}

		err = db.Patch(ctx, UsersTable, PartialUpdateUser{
			ID:  cris2.ID,
			Age: nullable.Int(29),
		})
		if err != nil {
			panic(err.Error())
		}

		return nil
	})
	if err != nil {
		panic(err.Error())
	}
}

支持的适配器

KSQL支持多种数据库适配器:

  1. Postgres (使用pgx v4):

    go get github.com/vingarcia/ksql/adapters/kpgx
    
  2. Postgres (使用pgx v5):

    go get github.com/vingarcia/ksql/adapters/kpgx5
    
  3. MySQL:

    go get github.com/vingarcia/ksql/adapters/kmysql
    
  4. SQLServer:

    go get github.com/vingarcia/ksql/adapters/ksqlserver
    
  5. SQLite3 (基于CGO):

    go get github.com/vingarcia/ksql/adapters/ksqlite3
    
  6. SQLite (无CGO):

    go get github.com/vingarcia/ksql/adapters/modernc-ksqlite
    

KSQL提供了简单而强大的API来操作SQL数据库,通过结构体标签和辅助方法简化了常见的数据库操作,同时保持了良好的性能。


更多关于golang简单强大的SQL数据库操作插件库KSQL的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang简单强大的SQL数据库操作插件库KSQL的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


KSQL: Golang简单强大的SQL数据库操作库

KSQL是一个轻量级但功能强大的Golang SQL数据库操作库,它提供了简单易用的API来执行常见的数据库操作。下面我将介绍KSQL的主要特性和使用方法。

KSQL主要特性

  1. 简单易用的API设计
  2. 支持多种数据库(MySQL, PostgreSQL, SQLite等)
  3. 自动映射结构体和数据库表
  4. 支持事务操作
  5. 内置SQL注入防护
  6. 支持链式调用

安装KSQL

go get github.com/vingarcia/ksql

基本使用方法

1. 初始化数据库连接

package main

import (
	"database/sql"
	"fmt"
	"log"

	"github.com/vingarcia/ksql"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// 使用标准库的sql.Open创建连接
	db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 创建KSQL适配器
	adapter := ksql.NewAdapter(db, ksql.Config{
		TableName: "users", // 默认表名
	})
	
	// 使用KSQL进行操作...
}

2. 定义模型结构体

type User struct {
	ID        int    `ksql:"id"`
	Name      string `ksql:"name"`
	Email     string `ksql:"email"`
	CreatedAt string `ksql:"created_at"`
}

3. CRUD操作示例

插入数据

user := User{
	Name:  "张三",
	Email: "zhangsan@example.com",
}

// 插入并返回ID
id, err := adapter.Insert(ksql.InsertOpts{
	TableName: "users",
	Record:    &user,
})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("插入成功,ID: %d\n", id)

查询单个记录

var user User
err := adapter.QueryOne(ksql.QueryOneOpts{
	TableName: "users",
	Record:    &user,
	Where:     ksql.Where("id = ?", 1),
})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("查询结果: %+v\n", user)

查询多个记录

var users []User
err := adapter.Query(ksql.QueryOpts{
	TableName: "users",
	Records:   &users,
	Where:     ksql.Where("name LIKE ?", "%张%"),
	Limit:     10,
})
if err != nil {
	log.Fatal(err)
}

for _, user := range users {
	fmt.Printf("用户: %+v\n", user)
}

更新数据

user := User{
	ID:    1,
	Name:  "张三(更新)",
	Email: "newemail@example.com",
}

rowsAffected, err := adapter.Update(ksql.UpdateOpts{
	TableName: "users",
	Record:    &user,
})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("更新了 %d 行\n", rowsAffected)

删除数据

rowsAffected, err := adapter.Delete(ksql.DeleteOpts{
	TableName: "users",
	Where:     ksql.Where("id = ?", 1),
})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("删除了 %d 行\n", rowsAffected)

4. 事务处理

err := adapter.Transaction(func(tx *ksql.Adapter) error {
	// 在事务中执行多个操作
	_, err := tx.Insert(ksql.InsertOpts{
		TableName: "users",
		Record: &User{
			Name:  "李四",
			Email: "lisi@example.com",
		},
	})
	if err != nil {
		return err
	}

	_, err = tx.Update(ksql.UpdateOpts{
		TableName: "users",
		Record: &User{
			ID:    2,
			Name:  "王五(更新)",
			Email: "wangwu@example.com",
		},
	})
	return err
})

if err != nil {
	log.Fatal("事务执行失败:", err)
}

5. 高级查询

// 使用Join查询
var result []struct {
	User  User   `ksql:"users"`
	Order Order  `ksql:"orders"`
}

err := adapter.Query(ksql.QueryOpts{
	TableName: "users",
	Records:   &result,
	Join:      "LEFT JOIN orders ON users.id = orders.user_id",
	Where:     ksql.Where("users.id > ?", 10),
})
if err != nil {
	log.Fatal(err)
}

// 使用Count统计
count, err := adapter.Count(ksql.CountOpts{
	TableName: "users",
	Where:     ksql.Where("name LIKE ?", "%张%"),
})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("共有 %d 个姓张的用户\n", count)

总结

KSQL提供了简单而强大的API来操作SQL数据库,它的主要优点包括:

  1. 简洁的API设计,减少了样板代码
  2. 自动映射结构体和数据库表
  3. 内置安全防护
  4. 支持事务处理
  5. 良好的错误处理

对于需要轻量级ORM但又不想使用复杂框架的Golang项目,KSQL是一个很好的选择。它既保留了SQL的灵活性,又提供了ORM的便利性。

更多高级用法和详细文档可以参考KSQL的GitHub仓库:https://github.com/vingarcia/ksql

回到顶部