diff --git a/g/database/gdb/gdb_model.go b/g/database/gdb/gdb_model.go index 0b7b1224e..77287e4f2 100644 --- a/g/database/gdb/gdb_model.go +++ b/g/database/gdb/gdb_model.go @@ -50,6 +50,7 @@ func (db *Db) From(tables string) (*Model) { // (事务)链式操作,数据表字段,可支持多个表,以半角逗号连接 func (tx *Tx) Table(tables string) (*Model) { return &Model { + db : tx.db, tx : tx, tables : tables, } @@ -139,7 +140,12 @@ func (md *Model) Data(data...interface{}) (*Model) { } // 链式操作, CURD - Insert/BatchInsert -func (md *Model) Insert() (sql.Result, error) { +func (md *Model) Insert() (result sql.Result, err error) { + defer func() { + if err == nil { + md.checkAndRemoveCache() + } + }() if md.data == nil { return nil, errors.New("inserting into table with empty data") } @@ -165,7 +171,12 @@ func (md *Model) Insert() (sql.Result, error) { } // 链式操作, CURD - Replace/BatchReplace -func (md *Model) Replace() (sql.Result, error) { +func (md *Model) Replace() (result sql.Result, err error) { + defer func() { + if err == nil { + md.checkAndRemoveCache() + } + }() if md.data == nil { return nil, errors.New("replacing into table with empty data") } @@ -191,7 +202,12 @@ func (md *Model) Replace() (sql.Result, error) { } // 链式操作, CURD - Save/BatchSave -func (md *Model) Save() (sql.Result, error) { +func (md *Model) Save() (result sql.Result, err error) { + defer func() { + if err == nil { + md.checkAndRemoveCache() + } + }() if md.data == nil { return nil, errors.New("replacing into table with empty data") } @@ -217,7 +233,12 @@ func (md *Model) Save() (sql.Result, error) { } // 链式操作, CURD - Update -func (md *Model) Update() (sql.Result, error) { +func (md *Model) Update() (result sql.Result, err error) { + defer func() { + if err == nil { + md.checkAndRemoveCache() + } + }() if md.data == nil { return nil, errors.New("updating table with empty data") } @@ -229,7 +250,12 @@ func (md *Model) Update() (sql.Result, error) { } // 链式操作, CURD - Delete -func (md *Model) Delete() (sql.Result, error) { +func (md *Model) Delete() (result sql.Result, err error) { + defer func() { + if err == nil { + md.checkAndRemoveCache() + } + }() if md.where == "" { return nil, errors.New("where is required while deleting") } @@ -251,11 +277,14 @@ func (md *Model) Batch(batch int) *Model { // name表示自定义的缓存名称,便于业务层精准定位缓存项(如果业务层需要手动清理时,必须指定缓存名称), // 例如:查询缓存时设置名称,清理缓存时可以给定清理的缓存名称进行精准清理。 func (md *Model) Cache(time int, name ... string) *Model { - md.cacheEnabled = true - md.cacheTime = time + md.cacheTime = time if len(name) > 0 { md.cacheName = name[0] } + // 查询缓存特性不支持事务操作 + if md.tx == nil { + md.cacheEnabled = true + } return md } @@ -325,15 +354,13 @@ func (md *Model) Count() (int, error) { } // 查询操作,对底层SQL操作的封装 -func (md *Model) getAll(sql string, args...interface{}) (Result, error) { - var err error - var result Result +func (md *Model) getAll(sql string, args...interface{}) (result Result, err error) { var cacheKey string // 查询缓存查询处理 - if md.cacheEnabled && md.tx == nil { + if md.cacheEnabled { cacheKey = md.cacheName if len(cacheKey) == 0 { - cacheKey = sql + cacheKey = sql + "/" + gconv.String(args) } if v := md.db.cache.Get(cacheKey); v != nil { return v.(Result), nil @@ -345,12 +372,23 @@ func (md *Model) getAll(sql string, args...interface{}) (Result, error) { result, err = md.tx.GetAll(sql, args...) } // 查询缓存保存处理 - if len(cacheKey) > 0 && md.cacheTime >= 0 { - md.db.cache.Set(cacheKey, result, md.cacheTime*1000) + if len(cacheKey) > 0 && err == nil { + if md.cacheTime < 0 { + md.db.cache.Remove(cacheKey) + } else { + md.db.cache.Set(cacheKey, result, md.cacheTime*1000) + } } return result, err } +// 检查是否需要查询查询缓存 +func (md *Model) checkAndRemoveCache() { + if md.cacheEnabled && md.cacheTime < 0 && len(md.cacheName) > 0 { + md.db.cache.Remove(md.cacheName) + } +} + // 格式化当前输入参数,返回可执行的SQL语句(不带参数) func (md *Model) getFormattedSql() string { if md.fields == "" { diff --git a/geg/database/mysql/gdb_cache.go b/geg/database/mysql/gdb_cache.go new file mode 100644 index 000000000..7a64287cc --- /dev/null +++ b/geg/database/mysql/gdb_cache.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "gitee.com/johng/gf/g/database/gdb" +) + +func main() { + gdb.AddDefaultConfigNode(gdb.ConfigNode { + Host : "127.0.0.1", + Port : "3306", + User : "root", + Pass : "123456", + Name : "test", + Type : "mysql", + Role : "master", + Charset : "utf8", + }) + db, err := gdb.New() + if err != nil { + panic(err) + } + // 开启调试模式,以便于记录所有执行的SQL + db.SetDebug(true) + + // 执行2次查询并将查询结果缓存3秒,并可执行缓存名称(可选) + for i := 0; i < 2; i++ { + r, _ := db.Table("user").Cache(3, "vip-user").Where("uid=?", 1).One() + fmt.Println(r.ToMap()) + } + + // 执行更新操作,并清理指定名称的查询缓存 + db.Table("user").Cache(-1, "vip-user").Data(gdb.Map{"name" : "smith"}).Where("uid=?", 1).Update() + + // 再次执行查询,启用查询缓存特性 + r, _ := db.Table("user").Cache(3, "vip-user").Where("uid=?", 1).One() + fmt.Println(r.ToMap()) + + for k, v := range db.GetQueriedSqls() { + fmt.Println(k, ":") + fmt.Println("Sql :", v.Sql) + fmt.Println("Args :", v.Args) + fmt.Println("Error:", v.Error) + fmt.Println("Cost :", v.Cost) + fmt.Println("Func :", v.Func) + } +} \ No newline at end of file diff --git a/geg/database/mysql/gdb_debug.go b/geg/database/mysql/gdb_debug.go index ba73a5fd4..a5bcbfccd 100644 --- a/geg/database/mysql/gdb_debug.go +++ b/geg/database/mysql/gdb_debug.go @@ -5,25 +5,22 @@ import ( "gitee.com/johng/gf/g/database/gdb" ) -var db *gdb.Db - -// 初始化配置及创建数据库 -func init () { - gdb.AddDefaultConfigNode(gdb.ConfigNode { - Host : "127.0.0.1", - Port : "3306", - User : "root", - Pass : "123456", - Name : "test", - Type : "mysql", - Role : "master", - Charset : "utf8", - }) - db, _ = gdb.New() -} - - func main() { + gdb.AddDefaultConfigNode(gdb.ConfigNode { + Host : "127.0.0.1", + Port : "3306", + User : "root", + Pass : "123456", + Name : "test", + Type : "mysql", + Role : "master", + Charset : "utf8", + }) + db, err := gdb.New() + if err != nil { + panic(err) + } + db.SetDebug(true) // 执行3条SQL查询 for i := 1; i <= 3; i++ { diff --git a/geg/other/test.go b/geg/other/test.go index f25e19111..e31b3c740 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,73 +2,17 @@ package main import ( "fmt" - "log" - "net" "time" + "errors" ) +func test() (err error) { + defer func() { + fmt.Println(err) + }() + time.Sleep(time.Second) + return errors.New("111") +} func main() { - addr := "127.0.0.1:8999" - - tcpaddr, err := net.ResolveTCPAddr("tcp4", addr) - if err != nil { - log.Fatal(err) - } - listener, err := net.ListenTCP("tcp", tcpaddr) - if err != nil { - log.Fatal(err) - } - - // Server - done := make(chan error) - go func(listener net.Listener, done chan<- error) { - for { - conn, err := listener.Accept() - if err != nil { - done <- err - return - } - go func(conn net.Conn) { - var buffer [1024]byte - n, err := conn.Read(buffer[:]) - if err != nil { - log.Println(err) - } else { - log.Println(">", string(buffer[0:n])) - } - if err := conn.Close(); err != nil { - log.Println("error closing server conn:", err) - } - }(conn) - } - }(listener, done) - - // Client - conn, err := net.Dial("tcp", addr) - if err != nil { - log.Fatal(err) - } - for i := 0; i < 2; i++ { - _, err := conn.Write([]byte("hello")) - if err != nil { - log.Println(err) - err = conn.Close() - if err != nil { - log.Println("error closing client conn:", err) - } - break - } - fmt.Println("ok") - time.Sleep(2 * time.Second) - } - - // Shut the server down and wait for it to report back - err = listener.Close() - if err != nil { - log.Fatal("error closing listener:", err) - } - err = <-done - if err != nil { - log.Println("server returned:", err) - } + test() } \ No newline at end of file