架构设计
7849
本篇介绍如何使用Golang访问MemFireDB数据库。
如果大家有个人项目或者公司内部测试项目,推荐大家尝试MemFire Cloud,不用自己搭建数据库,在家或者公司随时可以访问。
gopg是Golang中最常用的访问数据库的ORM库,MemFireDB兼容Postgres接口,所以可以直接把MemFireDB当Postgres使用。
在 memfiredb.com 上创建数据库时,可以选择创建密码或者证书两种认证模式,在公网上部署的数据库,如果存储的是比较重要的数据,建议使用证书认证模式,该模式安全系数要高很多,撞库、彩虹表、暴力破解等传统的密码破解方式对证书认证是无能为力的。如果只是简单测试,可以使用密码认证方式,这种方式配置简单些。
下面是示例代码:
import ( "context" "flag" "fmt" "github.com/go-pg/pg/v10" "github.com/go-pg/pg/v10/orm" "strings" "sync" ) var ( addr = flag.String("addr", "192.168.80.161:5433", "memfire address to connect") user = flag.String("user", "test", "memfire user") passwd = flag.String("passwd", "test", "memfire password") dbname = flag.String("db", "dbname", "memfire database name to connect") ) func panicIf(err error) { if err != nil { panic(err) } } func test_transaction_try_again(db *pg.DB) { incrInTx := func(db *pg.DB) error { // Transaction is automatically rolled back on error. return db.RunInTransaction(db.Context(), func(tx *pg.Tx) error { var counter int _, err := tx.QueryOne( pg.Scan(&counter), `SELECT counter FROM counters FOR UPDATE`) if err != nil { return err } counter++ _, err = tx.Exec(`UPDATE counters SET counter = ?`, counter) return err }) } var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() for { err := incrInTx(db) if err != nil { if strings.Contains(err.Error(), "40001") || strings.Contains(err.Error(), "Try again") || strings.Contains(err.Error(), "Restart read required") { fmt.Println("Try again") continue } panic(err) } break } }() } wg.Wait() } type Counter struct { Counter int64 } type User struct { Id int64 Name string Emails []string } // createSchema creates database schema for Counter/ User func createSchema(db *pg.DB) error { models := []interface{}{ (*Counter)(nil), (*User)(nil), } for _, model := range models { err := db.Model(model).CreateTable(&orm.CreateTableOptions{ Temp: false, IfNotExists: true, }) if err != nil { return err } } return nil } func main() { flag.Parse() opt := pg.Options{ Addr: *addr, User: *user, Password: *passwd, Database: *dbname, OnConnect: func(ctx context.Context, cn *pg.Conn) error { println("new connection created") return nil }, } db := pg.Connect(&opt) defer db.Close() err := createSchema(db) panicIf(err) _, err = db.Exec("delete from counters") panicIf(err) cnt := &Counter{ Counter: 1, } _, err = db.Model(cnt).Insert() panicIf(err) test_transaction_try_again(db) }