dbx

支持缓存全表数据的高性能 Golang DB 库
授权协议 MIT
开发语言 Google Go
所属分类 数据库相关、 数据库驱动程序
软件类型 开源软件
地区 国产
投 递 者 田马鲁
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

什么是 dbx ? 简而言之就是:

dbx = DB + Cache

它是一个支持对全表数据进行透明缓存的 Golang DB 库,在内存足够大的情况下,不再需要 Memcached, Redis 等缓存服务。 而且读取缓存的速度相当之快,本机测试 qps 达到: 350万+/秒,可以有效的简化应用端业务逻辑代码。

它支持 MySQL/Sqlite3,支持结构体自由组合嵌套。

它的实现原理为自动扫描表结构,确定主键和自增列,并且通过主键按照行来缓存数据,按照行透明管理 cache,上层只需要按照普通的 ORM 风格 API 操作即可。

支持缓存,高性能读取 KV 缓存全表数据

经过本机简单的测试(小数据下),直接查询 Sqlite3 速度可以达到 3万+/秒,开启缓存后达到恐怖的 350万+/秒。 一般针对高频访问的小表开启缓存:

db.Bind("user", &User{}, true)
db.Bind("group", &Group{}, true)
db.EnableCache(true)

支持嵌套,尽量避免低效反射

golang 为静态语言,在实现比较复杂的功能的时候往往要用到反射,而反射使用不当的时候会严重拖慢速度。经过实践发现,应该尽量使用数字索引,不要使用字符串索引,比如 Field() 性能大约是 FieldByName() 的 50 倍! 绝大部分 db 库不支持嵌套,因为反射又慢又复杂,特别是嵌套层数过多的时候。还好通过努力,dbx 高效的实现了无限制层数的嵌套支持,并且性能还不错。

type Human struct {
Age int64     `db:"age"`
}
type User struct {
Human
Uid        int64     `db:"uid"`
Gid        int64     `db:"gid"`
Name       string    `db:"name"`
CreateDate time.Time `db:"createDate"`
}

API 预览:

通过 golang 的反射特性,可以实现接近脚本语言级的便捷程度。如下:


// 打开数据库
db, err = dbx.Open("mysql", "root@tcp(localhost)/test?parseTime=true&charset=utf8")
// 插入一条
db.Table("user").Insert(user)
// 查询一条
db.Table("user").Where("uid=?", 1).One(&user)
// 通过主健查询一条
db.Table("user").WherePK(1).One(&user)
// 通过主健更新一条
db.Table("user").Update(&user)
// 通过主健删除一条
db.Table("user").WherePK(1).Delete()
// 获取多条
db.Table("user").Where("uid>?", 1).All(&userList)

日志输出到指定的流

可以自由的重定向日志数据流。

// 将 db 产生的错误信息输出到标准输出(控制台)
db.Stderr = os.Stdout
// 将 db 产生的错误信息输出到指定的文件
db.Stderr = dbx.OpenFile("./db_error.log") 
// 默认:将 db 的输出(主要为 SQL 语句)重定向到"黑洞"(不输出执行的 SQL 语句等信息)
db.Stdout = ioutil.Discard
// 默认:将 db 产生的输出(主要为 SQL 语句)输出到标准输出(控制台)
db.Stdout = os.Stdout

兼容原生的方法

有时候我们需要调用原生的接口,来实现比较复杂的目的。

// 自定义复杂 SQL 获取单条结果(原生)
var uid int64
err = db.QueryRow("SELECT uid FROM user WHERE uid=?", 2).Scan(&uid)
if err != nil {
panic(err)
}
fmt.Printf("uid: %v\n", uid)
db.Table("user").LoadCache() // 自定义需要手动刷新缓存

用例


package main

import (
	"github.com/mydeeplike/dbx"
	"fmt"
	"os"
	"time"
)

type User struct {
	Uid        int64     `db:"uid"`
	Gid        int64     `db:"gid"`
	Name       string    `db:"name"`
	CreateDate time.Time `db:"createDate"`
}

func main() {

	var err error
	var db *dbx.DB

	// db, err = dbx.Open("sqlite3", "./db1.db?cache=shared&mode=rwc&parseTime=true&charset=utf8") // sqlite3
	db, err = dbx.Open("mysql", "root@tcp(localhost)/test?parseTime=true&charset=utf8")            // mysql
	dbx.Check(err)
	defer db.Close()

	// db 输出信息设置
	db.Stdout = os.Stdout // 将 db 产生的信息(大部分为 sql 语句)输出到标准输出
	db.Stderr = dbx.OpenFile("./db_error.log") // 将 db 产生的错误信息输出到指定的文件
	// db.Stdout = ioutil.Discard // 默认:将 db 的输出信息重定向到"黑洞"(不输出执行的 SQL 语句等信息)

	// 参数设置
	db.SetMaxIdleConns(10)
	db.SetMaxOpenConns(10)
	// db.SetConnMaxLifetime(time.Second * 5)

	// 创建表
	_, err = db.Exec(`DROP TABLE IF EXISTS user;`)
	_, err = db.Exec(`CREATE TABLE user(
		uid        INT(11) PRIMARY KEY AUTO_INCREMENT,
		gid        INT(11) NOT NULL DEFAULT '0',
		name       TEXT             DEFAULT '',
		createDate DATETIME         DEFAULT CURRENT_TIMESTAMP
		);
	`)
	dbx.Check(err)

	// 开启缓存,可选项,一般只针对小表开启缓存,超过 10w 行,不建议开启!
	db.Bind("user2", &User{}, true)
	db.EnableCache(true)

	// 插入一条
	u1 := &User{1, 1, "jack", time.Now()}
	_, err = db.Table("user").Insert(u1)
	dbx.Check(err)

	// 读取一条
	u2 := &User{}
	err = db.Table("user").WherePK(1).One(u2)
	dbx.Check(err)
	fmt.Printf("%+v\n", u2)
	
	// 读取一条,判断是否存在
	err = db.Table("user").WherePK(1).One(u2)
	dbx.Check(err)
	if dbx.NoRows(err) {
		panic("not found.")
	}
	fmt.Printf("%+v\n", u2)

	// 更新一条
	u2.Name = "jack.ma"
	_, err = db.Table("user").Update(u2)
	dbx.Check(err)

	// 删除一条
	_, err = db.Table("user").WherePK(1).Delete()
	dbx.Check(err)

	// Where 条件 + 更新
	_, err = db.Table("user").WhereM(dbx.M{{"uid", 1}, {"gid", 1}}).UpdateM(dbx.M{{"Name", "jet.li"}})
	dbx.Check(err)

	// 插入多条
	for i := int64(0); i < 5; i++ {
		u := &User{
			Uid: i,
			Gid: i,
			Name: fmt.Sprintf("name-%v", i),
			CreateDate: time.Now(),
		}
		_, err := db.Table("user").Insert(u)
		if err != nil {
			panic(err)
		}
	}

	// 获取多条
	userList := []*User{}
	err = db.Table("user").Where("uid>?", 1).All(&userList)
	dbx.Check(err)
	for _, u := range userList {
		fmt.Printf("%+v\n", u)
	}

	// 批量更新
	_, err = db.Table("user").Where("uid>?", 3).UpdateM(dbx.M{{"gid", 10}})
	dbx.Check(err)

	// 批量删除
	_, err = db.Table("user").Where("uid>?", 3).Delete()
	if err != nil {
		panic(err)
	}

	// 总数
	n, err := db.Table("user").Where("uid>?", -1).Count()
	dbx.Check(err)
	fmt.Printf("count: %v\n", n)

	// 求和
	n, err = db.Table("user").Where("uid>?", -1).Sum("uid")
	dbx.Check(err)
	fmt.Printf("sum(uid): %v\n", n)

	// 求最大值
	n, err = db.Table("user").Where("uid>?", -1).Max("uid")
	dbx.Check(err)
	fmt.Printf("max(uid): %v\n", n)

	// 求最小值
	n, err = db.Table("user").Where("uid>?", -1).Min("uid")
	dbx.Check(err)
	fmt.Printf("min(uid): %v\n", n)

	// 自定义复杂 SQL 获取单条结果(原生)
	var uid int64
	err = db.QueryRow("SELECT uid FROM user WHERE uid=?", 2).Scan(&uid)
	dbx.Check(err)
	fmt.Printf("uid: %v\n", uid)
	db.Table("user").LoadCache() // 自定义需要手动刷新缓存

	// 自定义复杂 SQL 获取多条(原生)
	var name string
	rows, err := db.Query("SELECT `uid`, `name` FROM `user` WHERE 1 ORDER BY uid DESC")
	dbx.Check(err)
	rows.Close()
	for rows.Next() {
		rows.Scan(&uid, &name)
		fmt.Printf("uid: %v, name: %v\n", uid, name)
	}
	db.Table("user").LoadCache() // 自定义需要手动刷新缓存

	return
}

  • Sco-Unix调试工具dbx使用方法   1.     执行dbx $dbx 可执行文件名 可执行文件在编译的时候必须代上 –g 参数 2.     显示代码 (dbx)l                                            //从文件开头列出代码 (dbx)list                                       //从文件开头列出

  • 转自: http://blog.csdn.net/yaoyuhang/archive/2006/03/23/636062.aspx dbx  命令   用途   提供了一个调试和运行程序的环境。   语法  dbx [ -a ProcessID ] [ -c CommandFile ] [ -d NestingDepth ] [ -I Directory ] [ -E DebugEnvironme

  • 使用 dbx 调试程序 可能出于下列原因之一调试程序: 为了确定程序在何处以及为何导致崩溃。确定崩溃原因的方法包括: 在 dbx 中运行程序。dbx 会报告崩溃的发生位置。 检查信息转储文件并查看堆栈跟踪(请参见检查信息转储文件 and 查看调用堆栈)。 为了确定程序为何给出错误结果。其方法包括: 设置用于停止执行的断点,以便可以检查程序的状态以及查看变量值(请参见设置断点和检查变量)。 按一次执

  • 使用 dbx 调试程序 可能出于下列原因之一调试程序: 为了确定程序在何处以及为何导致崩溃。确定崩溃原因的方法包括: 在 dbx 中运行程序。dbx 会报告崩溃的发生位置。 检查核心转储文件并查看栈跟踪(请参见检查核心转储文件 and 查看调用栈)。 为了确定程序为何给出错误结果。其方法包括: 设置用于停止执行的断点,以便可以检查程序的状态以及查看变量值(请参见设置断点和检查变量)。 按一次执行一

 相关资料
  • 一个好的HTTP缓存策略可以极大地提高一个web应用的性能及客户端的体验。谈到HTTP缓存,它主要是与HTTP的响应头'Cache-Control'相关,其次另外的一些响应头比如'Last-Modified'和'ETag'等也会起一定的作用。 HTTP的响应头'Cache-Control'主要帮助私有缓存(比如浏览器端缓存)和公共缓存(比如代理端缓存)了解它们应该如果缓存HTTP响应,以便后用。

  • 我试图测试Spring数据JPA存储库(扩展)的Spring缓存支持(如本文所述),但我的配置确实有问题。 下面是我的测试: 通过运行上面的测试,我注意到类型的对象作为键传递给,而null作为值传递给: 下面是堆栈跟踪:

  • 一个轻量级的缓存实现,目前已支持 Redis Memcache Memcached File 四种储存模式 仓库地址: Github 安装 composer require easyswoole/cache 注意: 请确保框架已经引入了 composer 的 autoload.php 文件,否则报类不存在的错误 快速入门 如果不做任何设置,默认使用File驱动,开箱即用 use easySwool

  • 问题内容: 我需要一些想法来实现Java的(真正)高性能内存数据库/存储机制。在存储20,000+个Java对象的范围内,每5秒钟左右更新一次。 我愿意接受的一些选择: 纯JDBC /数据库组合 JDO JPA / ORM /数据库组合 对象数据库 其他存储机制 我最好的选择是什么?你有什么经验? 编辑:我还需要能够查询这些对象 问题答案: 您可以尝试使用Prevayler之类的工具(基本上是一个

  • 我已经在solrcloud 4.3.0中为我的索引配置了solr缓存。我还将自动提交策略配置为1h hard commit和opensearcher false。虽然我没有重新打开searcher,但似乎每1小时我的缓存就会被刷新并重置。据我所知,只有关闭和打开新的搜索程序才能导致缓存被刷新。但我不明白为什么会这样?

  • 我在应用程序中尝试将Spring缓存与ehcache结合使用时遇到了一个问题。由于无法详细说明的原因,我的应用程序使用BeanFactory图而不是ApplicationContext。正如Spring文档中所述,只要我们手动注册BeanPostProcessor,这种方法就可以很好地工作。 我们现在正在为应用程序添加缓存。当我们使用最简单的注释配置时,它可以工作。 //这很有效 我们将其配置为为

  • Django试图尽可能多的支持所有数据库后端的特性。然而,并不是所有数据库都一样,所以我们必须在支持哪些特性和做出哪些安全的假定上做出设计决策。 本文描述了一些Django使用数据库的有关特性。当然,它并不想成为各服务器指定的文档或者参考手册的替代品。 综合说明 持续连接特性 持续连接的特性避免了每一次重新建立与数据库的连接的请求中所增加的压力。这些连接通过 CONN_MAX_AGE 参数(控制一