软件简介

什么是 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
}


展开阅读全文

代码

的 Gitee 指数为
超过 的项目

评论 (0)

加载中
更多评论
暂无内容
发表了博客
2016/08/01 21:28

bmp文件生成

void CTestSaveBmpView::SaveAsBmp(CString filename) { //定义图形大小 int iWidth = 800; int iHeight = 600; int iPixel = 16; //图形格式参数 LPBITMAPINFO lpbmih = new BITMAPINFO; lpbmih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbmih->bmiHeader.biWidth = iWidth; lpbmih->bmiHeader.biHeight = iHeight; lpbmih->bmiHeader.biPlanes = 1; lpbmih->bmiHeader.biBitCount = iPixel; lpbmih->bmiHeader.biComp...

0
0
发表了博客
2012/05/24 18:14

php测试中小技巧(省去不少时间)

从开源代码中看到的,拿出来和大家分享 function dbx() { echo '<pre>'; if(func_num_args()){ foreach (func_get_args() as $k => $v) { echo "------- dbx $k -------<br/>"; print_r($v); echo "<br/>"; } }; echo '</pre>'; } function dbt() { echo '<pre>'; if(func_num_args()){ foreach (func_get_args() as $k => $v) { echo "------- dbx $k -------<br/>"; echo "<textarea cols=20 rows=6>"; print_r($v); echo "</...

0
0
发表了博客
2019/07/01 13:26

FastReport For Delphi7 通用安装方法

安装前请册除原有的FR控件。 1. "Tools|Environmet options..."中的"Library"标签面下"Library path"添加FastReport路径。 FastReport\FastQB FastReport\FastScript FastReport\Source FastReport\Source\BDE FastReport\Source\ADO FastReport\Source\IBX FastReport\Source\DBX FastReport\Source\ExportPack 2. 生成汉化文件 运行"recompile.exe"文件,设置相应选项,我的设置如下: 1.Select the compiler 设置为 Delphi7 ...

0
0
发表了博客
2015/08/18 11:11

【原创】GCC选项-g和-ggdb的区别

很多人不清楚 gcc 编译选项 -g 和 -ggdb 的区别是什么,这里根据 stackoverflow 上的一个帖子,以及相关手册上的内容进行解释说明。 Debugging-Options of GCC 手册说明 -g Produce debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF 2). GDB can work with this debugging information. -g 选项可以产生符合操作系统本地格式的调试信息(stabs、COFF、XCOFF ,或者 DWARF 2)。G...

0
5
发表了博客
2018/04/03 21:20

Delphi 使用 Datasnap 的几种三层应用技术总结

Delphi 使用 Datasnap 进行三层应用开发,积累了几种技术,总结如下: 1、(推荐!)在 Datasnap 服务端 使用 TDatasetProvider,客户端 使用 TDSProviderConnection 1)采用 Datasnap Server ,可以使用TCP/IP、Http 通信。TDatasetProvider 能够提供 “元数据与业务数据”。 推荐:采用(FireDac技术) TFDConnection 连接数据库,通过 TFDQuery/TFDTable 向 TDatasetProvider 提供数据集;(!执持数据库新版本) 注意:也可...

0
2
2020/01/20 00:35

float精度计算测试

``` package main import ( "fmt" "github.com/go-ozzo/ozzo-dbx" _ "github.com/go-sql-driver/mysql" ) type DecimalDemo struct { Id int Amount float64 } func main() { db, _ := dbx.Open("mysql", "root:password@/test") var a float64 = 0.0003 var b float64 = 0.0002 var c float64 = a - b fmt.Println("c:", c) var d float64 = a * b demo := &DecimalDemo{ Id:0, Amount:d, } db.Model(demo).Insert() } ```...

0
0
发表了博客
2019/06/24 00:09

cad.arx 自定义实体之编译第一个项目(甜头)

本篇不从零开始讲如何制造自定义图元,而是教新手们如何设置了环境之后编译张帆书中的代码. 利用vs2010编译 张帆<AutoCAD ObjectARX(VC)开发基础与实例教程>一书中的自定义图元课程代码. 因为张帆都敲完了,我们肯定要先编译一下他的,再仔细地去看他的书,来学习c++, 看懂代码这种事情,就教给各位自己去学习.... 诉求点: 张帆书中所使用的vs2005很破旧,但是开发环境必须有,它有平台集v80. 而vs2010敲代码比vs2005好,ctrl+鼠标滚大...

0
0
发表了博客
2019/04/10 10:10

问题:程序编译通过,但是执行时报错:coredump

问题描述:    在一个客户现场搭建环境时,遇到了一个棘手的问题,C代码编译通过后,无法正常运行,启动会出现“coredump”错误。   运行环境为新搭建的AIX6.1,数据库为Oracle11.2.0.2.0。   将平台的C代码部署到用户下之后,makefile编译成功,之后启动程序,发现无法正常运行,启动会出现“coredump”错误。 问题排查:   根据dbx工具定位的代码位置,检查代码并未发现内存泄漏、越界等bug;到这就卡住了。   为了...

0
0
发表了博客
2012/10/12 15:47

Outlook常见问题解决方案

0x800CCC0D   找不到主机(检查您的SMTP服务器是不是设错,亦可能是对方Server 的问题,例如 Mail Server 没有开机、对方的DNS 服务器死掉了等等) 0x800ccc78   根据提供的错误代码查询,是Outlook Express中没有设置“我的服务器要求身份验证”所导致。解决方法:先设置“我的服务器要求身份验证”即可。如果您按照以上方法操作之后仍然无法正常使用,则可能是受到网络不稳定或者软件问题的原因而导致的,建议您可以更换新...

0
0
没有更多内容
加载失败,请刷新页面
点击加载更多
加载中
下一页
暂无内容
0 评论
14 收藏
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部