<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          dbx支持緩存全表數(shù)據(jù)的高性能 Golang DB 庫

          聯(lián)合創(chuàng)作 · 2023-09-30 20:03

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

          dbx = DB + Cache

          它是一個支持對全表數(shù)據(jù)進(jìn)行透明緩存的 Golang DB 庫,在內(nèi)存足夠大的情況下,不再需要 Memcached, Redis 等緩存服務(wù)。 而且讀取緩存的速度相當(dāng)之快,本機(jī)測試 qps 達(dá)到: 350萬+/秒,可以有效的簡化應(yīng)用端業(yè)務(wù)邏輯代碼。

          它支持 MySQL/Sqlite3,支持結(jié)構(gòu)體自由組合嵌套。

          它的實(shí)現(xiàn)原理為自動掃描表結(jié)構(gòu),確定主鍵和自增列,并且通過主鍵按照行來緩存數(shù)據(jù),按照行透明管理 cache,上層只需要按照普通的 ORM 風(fēng)格 API 操作即可。

          支持緩存,高性能讀取 KV 緩存全表數(shù)據(jù)

          經(jīng)過本機(jī)簡單的測試(小數(shù)據(jù)下),直接查詢 Sqlite3 速度可以達(dá)到 3萬+/秒,開啟緩存后達(dá)到恐怖的 350萬+/秒。 一般針對高頻訪問的小表開啟緩存:

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

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

          golang 為靜態(tài)語言,在實(shí)現(xiàn)比較復(fù)雜的功能的時候往往要用到反射,而反射使用不當(dāng)?shù)臅r候會嚴(yán)重拖慢速度。經(jīng)過實(shí)踐發(fā)現(xiàn),應(yīng)該盡量使用數(shù)字索引,不要使用字符串索引,比如 Field() 性能大約是 FieldByName() 的 50 倍! 絕大部分 db 庫不支持嵌套,因?yàn)榉瓷溆致謴?fù)雜,特別是嵌套層數(shù)過多的時候。還好通過努力,dbx 高效的實(shí)現(xiàn)了無限制層數(shù)的嵌套支持,并且性能還不錯。

          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 預(yù)覽:

          通過 golang 的反射特性,可以實(shí)現(xiàn)接近腳本語言級的便捷程度。如下:

          
          // 打開數(shù)據(jù)庫
          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)
          
          

          日志輸出到指定的流

          可以自由的重定向日志數(shù)據(jù)流。

          // 將 db 產(chǎn)生的錯誤信息輸出到標(biāo)準(zhǔn)輸出(控制臺)
          db.Stderr = os.Stdout
          // 將 db 產(chǎn)生的錯誤信息輸出到指定的文件
          db.Stderr = dbx.OpenFile("./db_error.log") 
          // 默認(rèn):將 db 的輸出(主要為 SQL 語句)重定向到"黑洞"(不輸出執(zhí)行的 SQL 語句等信息)
          db.Stdout = ioutil.Discard
          // 默認(rèn):將 db 產(chǎn)生的輸出(主要為 SQL 語句)輸出到標(biāo)準(zhǔn)輸出(控制臺)
          db.Stdout = os.Stdout
          
          

          兼容原生的方法

          有時候我們需要調(diào)用原生的接口,來實(shí)現(xiàn)比較復(fù)雜的目的。

          // 自定義復(fù)雜 SQL 獲取單條結(jié)果(原生)
          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 輸出信息設(shè)置
          	db.Stdout = os.Stdout // 將 db 產(chǎn)生的信息(大部分為 sql 語句)輸出到標(biāo)準(zhǔn)輸出
          	db.Stderr = dbx.OpenFile("./db_error.log") // 將 db 產(chǎn)生的錯誤信息輸出到指定的文件
          	// db.Stdout = ioutil.Discard // 默認(rèn):將 db 的輸出信息重定向到"黑洞"(不輸出執(zhí)行的 SQL 語句等信息)
          
          	// 參數(shù)設(shè)置
          	db.SetMaxIdleConns(10)
          	db.SetMaxOpenConns(10)
          	// db.SetConnMaxLifetime(time.Second * 5)
          
          	// 創(chuàng)建表
          	_, 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)
          
          	// 開啟緩存,可選項(xiàng),一般只針對小表開啟緩存,超過 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)
          	}
          
          	// 總數(shù)
          	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)
          
          	// 自定義復(fù)雜 SQL 獲取單條結(jié)果(原生)
          	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() // 自定義需要手動刷新緩存
          
          	// 自定義復(fù)雜 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
          }
          
          
          
          瀏覽 23
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          編輯 分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费少妇av | 无码 人妻 精 | 日日干日日干 | 日韩黄在线 | 黄色小电影黄色小视频 |