改进gf orm以及redis客户端的封装

This commit is contained in:
John
2018-04-24 23:09:59 +08:00
parent 8bc5dc75a6
commit 78e511573f
15 changed files with 174 additions and 308 deletions

View File

@ -11,11 +11,10 @@ import (
"fmt"
"errors"
"database/sql"
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/util/grand"
_ "github.com/lib/pq"
_ "github.com/go-sql-driver/mysql"
"gitee.com/johng/gf/g/util/gconv"
)
const (
@ -96,32 +95,6 @@ type Map map[string]interface{}
// 关联数组列表(索引从0开始的数组),绑定多条记录
type List []Map
// 获得默认/指定分组名称的数据库操作对象单例
func Instance (groupName...string) (*Db, error) {
name := config.d
if len(groupName) > 0 {
name = groupName[0]
}
return instance(name)
}
// 根据配置项获取一个数据库操作对象单例
func instance (groupName string) (*Db, error) {
instanceName := "gdb_instance_" + groupName
result := gcache.Get(instanceName)
if result == nil {
db, err := New(groupName)
if err == nil {
gcache.Set(instanceName, db, 0)
return db, nil
} else {
return nil, err
}
} else {
return result.(*Db), nil
}
}
// 使用默认/指定分组配置进行连接数据库集群配置项default
func New(groupName...string) (*Db, error) {
name := config.d
@ -161,11 +134,6 @@ func New(groupName...string) (*Db, error) {
}
}
// 根据单点数据库配置获得一个数据库草最对象
func NewByNode(node ConfigNode) (*Db, error) {
return newDb (&node, nil)
}
// 按照负载均衡算法(优先级配置)从数据库集群中选择一个配置节点出来使用
func getConfigNodeByPriority (cg *ConfigGroup) *ConfigNode {
if len(*cg) < 2 {
@ -210,10 +178,7 @@ func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) {
return nil, err
}
}
//link.setLink(link)
//link.setMaster(master)
//link.setSlave(slave)
//link.setQuoteChar(link.getQuoteCharLeft(), link.getQuoteCharRight())
return &Db {
link : link,
master : master,

View File

@ -37,7 +37,7 @@ type ConfigNode struct {
Name string // 数据库名称
Type string // 数据库类型mysql, sqlite, mssql, pgsql, oracle(目前仅支持mysql)
Role string // (可选默认为master)数据库的角色用于主从操作分离至少需要有一个master参数值master, slave
Charset string // (可选,默认为 utf-8)编码,默认为 utf-8
Charset string // (可选,默认为 utf8)编码,默认为 utf8
Priority int // (可选)用于负载均衡的权重计算,当集群中只有一个节点时,权重没有任何意义
Linkinfo string // (可选)自定义链接信息,当该字段被设置值时,以上链接字段(Host,Port,User,Pass,Name)将失效(该字段是一个扩展功能)
}
@ -55,7 +55,7 @@ var DatabaseConfiguration = Config {
Name : "test",
Type : "mysql",
Role : "master",
Charset : "utf-8",
Charset : "utf8",
Priority : 100,
},
{
@ -66,7 +66,7 @@ var DatabaseConfiguration = Config {
Name : "test",
Type : "mysql",
Role : "slave",
Charset : "utf-8",
Charset : "utf8",
Priority : 100,
},
},
@ -100,45 +100,6 @@ func AddConfigNode (group string, node ConfigNode) {
config.Unlock()
}
// 添加一台数据库服务器配置,通过解析规范的字符串配置实现
// 配置格式:账号@地址:端口,密码,数据库名称,数据库类型[,集群角色(master|slave),字符编码,负载均衡优先级,自定义链接]
//func AddConfigNodeByString (group string, nodestr string) {
// reg, _ := regexp.Compile(`(.+)@(.+):([^,]+),([^,]+),([^,]+),([^,]+)`)
// match := reg.FindStringSubmatch(nodestr)
// if match != nil {
// node := ConfigNode{
// User : strings.TrimSpace(match[1]),
// Host : strings.TrimSpace(match[2]),
// Port : strings.TrimSpace(match[3]),
// Pass : strings.TrimSpace(match[4]),
// Name : strings.TrimSpace(match[5]),
// Type : strings.TrimSpace(match[6]),
// }
// if len(match[0]) + 1 < len(nodestr) {
// extra := strings.Split(nodestr[len(match[0]) + 1:], ",")
// if len(extra) > 0 {
// node.Role = strings.TrimSpace(extra[0])
// }
// if len(extra) > 1 {
// node.Charset = strings.TrimSpace(extra[1])
// }
// if len(extra) > 2 {
// node.Priority, _ = strconv.Atoi(strings.TrimSpace(extra[2]))
// }
// if len(extra) > 3 {
// index := len(extra[0]) + len(extra[1]) + len(extra[2]) + 3
// node.Linkinfo = strings.TrimSpace(nodestr[len(match[0]) + 1 + index:])
// }
// }
// AddConfigNode(group, node)
// }
//}
// 添加默认链接的一台数据库服务器配置,通过解析规范的字符串配置实现
//func AddDefaultConfigNodeByString (nodestr string) {
// AddConfigNodeByString(gDEFAULT_CONFIG_GROUP_NAME, nodestr)
//}
// 添加默认链接的一台数据库服务器配置
func AddDefaultConfigNode (node ConfigNode) {
AddConfigNode(gDEFAULT_CONFIG_GROUP_NAME, node)

View File

@ -11,6 +11,8 @@ package gredis
import (
"time"
"github.com/gomodule/redigo/redis"
"gitee.com/johng/gf/g/container/gmap"
"gitee.com/johng/gf/g/util/gconv"
)
const (
@ -22,9 +24,8 @@ const (
// Redis客户端
type Redis struct {
address string
db interface{}
pool *redis.Pool
conn redis.Conn
pool *redis.Pool
}
// Redis链接池统计信息
@ -32,27 +33,45 @@ type PoolStats struct {
redis.PoolStats
}
// 连接池map
var pools = gmap.NewStringInterfaceMap()
// 创建redis操作对象
// address参数格式 host:port
func New(address string, db ... interface{}) *Redis {
r := &Redis{}
r.address = address
dialDb := 0
if len(db) > 0 {
r.db = db[0]
dialDb = gconv.Int(db[0])
}
r.pool = &redis.Pool {
MaxIdle : gDEFAULT_POOL_MAX_IDLE,
MaxActive : gDEFAULT_POOL_MAX_ACTIVE,
IdleTimeout : gDEFAULT_POOL_IDLE_TIMEOUT,
MaxConnLifetime : gDEFAULT_POOL_MAX_LIFE_TIME,
Dial : r.dialFunc(),
poolKey := address + "," + gconv.String(dialDb)
if v := pools.Get(poolKey); v == nil {
pool := &redis.Pool {
MaxIdle : gDEFAULT_POOL_MAX_IDLE,
MaxActive : gDEFAULT_POOL_MAX_ACTIVE,
IdleTimeout : gDEFAULT_POOL_IDLE_TIMEOUT,
MaxConnLifetime : gDEFAULT_POOL_MAX_LIFE_TIME,
Dial : func() (redis.Conn, error) {
c, err := redis.Dial("tcp", address)
if err != nil {
return nil, err
}
c.Do("SELECT", dialDb)
return c, nil
},
}
pools.Set(poolKey, pool)
r.pool = pool
} else {
r.pool = v.(*redis.Pool)
}
r.conn = r.pool.Get()
return r
}
// 关闭链接
func (r *Redis) Close() error {
return r.pool.Close()
return r.conn.Close()
}
// 设置属性 - MaxIdle
@ -82,26 +101,11 @@ func (r *Redis) Stats() *PoolStats {
// 执行命令 - Do
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
c := r.pool.Get()
defer c.Close()
return c.Do(command, args...)
return r.conn.Do(command, args...)
}
// 执行命令 - Send
func (r *Redis) Send(command string, args ...interface{}) error {
c := r.pool.Get()
defer c.Close()
return c.Send(command, args...)
return r.conn.Send(command, args...)
}
// 构造链接redis方法
func (r *Redis) dialFunc() func()(redis.Conn, error) {
return func() (redis.Conn, error) {
c, err := redis.Dial("tcp", r.address)
if err != nil {
return nil, err
}
c.Do("SELECT", r.db)
return c, nil
}
}

View File

@ -9,25 +9,17 @@
package gins
import (
"strconv"
"strings"
"gitee.com/johng/gf/g/os/gcfg"
"gitee.com/johng/gf/g/os/gcmd"
"gitee.com/johng/gf/g/os/genv"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/os/gfsnotify"
"gitee.com/johng/gf/g/database/gdb"
"gitee.com/johng/gf/g/container/gmap"
"gitee.com/johng/gf/g/database/gredis"
)
const (
gFRAME_CORE_COMPONENT_NAME_VIEW = "gf.core.component.view"
gFRAME_CORE_COMPONENT_NAME_CONFIG = "gf.core.component.config"
gFRAME_CORE_COMPONENT_NAME_DATABASE = "gf.core.component.database"
gFRAME_CORE_COMPONENT_NAME_REDIS = "gf.core.component.redis"
)
// 单例对象存储器
@ -43,35 +35,6 @@ func Set(k string, v interface{}) {
instances.Set(k, v)
}
// 自定义框架核心组件View
func SetView(v *gview.View) {
instances.Set(gFRAME_CORE_COMPONENT_NAME_VIEW, v)
}
// 自定义框架核心组件Config
func SetConfig(v *gcfg.Config) {
instances.Set(gFRAME_CORE_COMPONENT_NAME_CONFIG, v)
}
// 自定义框架核心组件Database
func SetDatabase(v *gdb.Db, name...string) {
dbCacheKey := gFRAME_CORE_COMPONENT_NAME_DATABASE
if len(name) > 0 {
dbCacheKey += name[0]
}
instances.Set(dbCacheKey, v)
}
// 自定义框架核心组件Redis
func SetRedis(v *gredis.Redis, name...string) {
dbCacheKey := gFRAME_CORE_COMPONENT_NAME_REDIS
if len(name) > 0 {
dbCacheKey += name[0]
}
instances.Set(dbCacheKey, v)
}
// 核心对象View
func View() *gview.View {
result := Get(gFRAME_CORE_COMPONENT_NAME_VIEW)
@ -112,106 +75,3 @@ func Config() *gcfg.Config {
}
return nil
}
// 核心对象Database
func Database(name...string) *gdb.Db {
dbCacheKey := gFRAME_CORE_COMPONENT_NAME_DATABASE
if len(name) > 0 {
dbCacheKey += name[0]
}
result := Get(dbCacheKey)
if result != nil {
return result.(*gdb.Db)
} else {
config := Config()
if config == nil {
return nil
}
if m := config.GetMap("database"); m != nil {
for group, v := range m {
if list, ok := v.([]interface{}); ok {
for _, nodev := range list {
node := gdb.ConfigNode{}
nodem := nodev.(map[string]interface{})
if value, ok := nodem["host"]; ok {
node.Host = value.(string)
}
if value, ok := nodem["port"]; ok {
node.Port = value.(string)
}
if value, ok := nodem["user"]; ok {
node.User = value.(string)
}
if value, ok := nodem["pass"]; ok {
node.Pass = value.(string)
}
if value, ok := nodem["name"]; ok {
node.Name = value.(string)
}
if value, ok := nodem["type"]; ok {
node.Type = value.(string)
}
if value, ok := nodem["role"]; ok {
node.Role = value.(string)
}
if value, ok := nodem["charset"]; ok {
node.Charset = value.(string)
}
if value, ok := nodem["priority"]; ok {
node.Priority, _ = strconv.Atoi(value.(string))
}
gdb.AddConfigNode(group, node)
}
}
}
// 这里不能用Instance方法否则无法自动检测更新
if db, err := gdb.New(name...); err == nil {
Set(dbCacheKey, db)
// 监控配置变化,一单有变化马上清空单例对象,下一次重新获取
// 无法对特定操作进行判断,不同编辑器的行为引起的操作回调提醒不一样
gfsnotify.Add(config.GetFilePath(), func(event *gfsnotify.Event) {
Set(dbCacheKey, nil)
})
return db
} else {
return nil
}
}
}
return nil
}
// 核心对象Redis
func Redis(name...string) *gredis.Redis {
group := "default"
redisCacheKey := gFRAME_CORE_COMPONENT_NAME_REDIS
if len(name) > 0 {
group = name[0]
redisCacheKey += name[0]
}
result := Get(redisCacheKey)
if result != nil {
return result.(*gredis.Redis)
} else {
config := Config()
if config == nil {
return nil
}
if m := config.GetMap("redis"); m != nil {
if v, ok := m[group]; ok {
array := strings.Split(gconv.String(v), ",")
if len(array) > 1 {
redis := gredis.New(array[0], array[1])
Set(redisCacheKey, redis)
// 监控配置变化,一单有变化马上清空单例对象,下一次重新获取
// 无法对特定操作进行判断,不同编辑器的行为引起的操作回调提醒不一样
gfsnotify.Add(config.GetFilePath(), func(event *gfsnotify.Event) {
Set(redisCacheKey, nil)
})
return redis
}
}
}
}
return nil
}

103
g/g.go
View File

@ -3,11 +3,19 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// 常用数据类型以及对象封装
package g
import (
"html/template"
"strings"
"strconv"
"gitee.com/johng/gf/g/os/gview"
"gitee.com/johng/gf/g/os/gcfg"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/frame/gins"
"gitee.com/johng/gf/g/database/gdb"
"gitee.com/johng/gf/g/database/gredis"
)
// 常用map数据结构
@ -16,8 +24,93 @@ type Map map[string]interface{}
// 常用list数据结构
type List []Map
// 输出到模板页面时保留HTML标签原意不做自动escape处理
func HTML(content string) template.HTML {
return template.HTML(content)
// 核心对象View
func View() *gview.View {
return gins.View()
}
// Config配置管理对象
// 配置文件目录查找依次为启动参数cfgpath、当前程序运行目录
func Config() *gcfg.Config {
return gins.Config()
}
// 数据库操作对象,使用了连接池
func Database(name...string) *gdb.Db {
config := gins.Config()
if config == nil {
return nil
}
if m := config.GetMap("database"); m != nil {
c := gdb.Config{}
for group, v := range m {
cg := gdb.ConfigGroup{}
if list, ok := v.([]interface{}); ok {
for _, nodev := range list {
node := gdb.ConfigNode{}
nodem := nodev.(map[string]interface{})
if value, ok := nodem["host"]; ok {
node.Host = gconv.String(value)
}
if value, ok := nodem["port"]; ok {
node.Port = gconv.String(value)
}
if value, ok := nodem["user"]; ok {
node.User = gconv.String(value)
}
if value, ok := nodem["pass"]; ok {
node.Pass = gconv.String(value)
}
if value, ok := nodem["name"]; ok {
node.Name = gconv.String(value)
}
if value, ok := nodem["type"]; ok {
node.Type = gconv.String(value)
}
if value, ok := nodem["role"]; ok {
node.Role = gconv.String(value)
}
if value, ok := nodem["charset"]; ok {
node.Charset = gconv.String(value)
}
if value, ok := nodem["priority"]; ok {
node.Priority, _ = strconv.Atoi(gconv.String(value))
}
cg = append(cg, node)
}
}
c[group] = cg
}
gdb.SetConfig(c)
if db, err := gdb.New(name...); err == nil {
return db
} else {
return nil
}
}
return nil
}
// Redis操作对象使用了连接池
func Redis(name...string) *gredis.Redis {
group := "default"
if len(name) > 0 {
group = name[0]
}
config := gins.Config()
if config == nil {
return nil
}
if m := config.GetMap("redis"); m != nil {
if v, ok := m[group]; ok {
array := strings.Split(gconv.String(v), ",")
if len(array) > 1 {
return gredis.New(array[0], array[1])
}
}
}
return nil
}

View File

@ -5,6 +5,7 @@ import (
"time"
"gitee.com/johng/gf/g/database/gdb"
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/frame/gins"
)
// 本文件用于gf框架的mysql数据库操作示例不作为单元测试使用
@ -13,17 +14,20 @@ var db *gdb.Db
// 初始化配置及创建数据库
func init () {
gdb.AddDefaultConfigNode(gdb.ConfigNode {
Host : "127.0.0.1",
Port : "3306",
User : "root",
Pass : "8692651",
Name : "test",
Type : "mysql",
Role : "master",
Charset : "utf8",
})
db, _ = gdb.Instance()
//gdb.AddDefaultConfigNode(gdb.ConfigNode {
// Host : "127.0.0.1",
// Port : "3306",
// User : "root",
// Pass : "8692651",
// Name : "test",
// Type : "mysql",
// Role : "master",
// Charset : "utf8",
//})
//db, _ = gdb.New()
gins.Config().SetPath("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame")
db = g.Database()
//gdb.SetConfig(gdb.ConfigNode {
// Host : "127.0.0.1",
@ -444,9 +448,9 @@ func keepPing() {
// 数据库单例测试在mysql中使用 show full processlist 查看链接信息
func instance() {
fmt.Println("instance:")
db1, _ := gdb.Instance()
db2, _ := gdb.Instance()
db3, _ := gdb.Instance()
db1, _ := gdb.New()
db2, _ := gdb.New()
db3, _ := gdb.New()
for {
fmt.Println("ping...")
db1.PingMaster()

View File

@ -8,6 +8,7 @@ import (
func main() {
redis := gredis.New("127.0.0.1:6379", 1)
defer redis.Close()
redis.Do("SET", "k1", "v1")
redis.Do("SET", "k2", "v2")
v1, _ := redis.Do("GET", "k1")

View File

@ -1,18 +0,0 @@
package main
import (
"time"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/frame/gins"
)
func main() {
gins.Config().SetPath("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame")
gtime.SetInterval(2*time.Second, func() bool {
redis := gins.Redis("cache")
redis.Do("GET", "k")
return true
})
select{}
}

View File

@ -6,20 +6,20 @@ database:
- host: 127.0.0.1
port: 3306
user: root
pass: 123456
pass: "8692651"
name: test
type: mysql
role: master
charset: utf-8
charset: utf8
priority: 1
- host: 127.0.0.1
port: 3306
user: root
pass: 123456
pass: "8692651"
name: test
type: mysql
role: master
charset: utf-8
charset: utf8
priority: 1
# Redis数据库配置
redis:

View File

@ -2,12 +2,12 @@ package demo
import (
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/frame/gins"
"gitee.com/johng/gf/g"
)
func init() {
ghttp.GetServer().BindHandler("/template2", func(r *ghttp.Request){
content, _ := gins.View().Parse("index.tpl", map[string]interface{}{
content, _ := g.View().Parse("index.tpl", map[string]interface{}{
"id" : 123,
"name" : "john",
})

View File

@ -2,15 +2,11 @@ package main
import (
"fmt"
"strings"
"gitee.com/johng/gf/g"
)
func main() {
s1 := `C:\Documents and Settings\Claymore\桌面\gf.test`
s2 := `C:\Documents and Settings\Claymore\桌面\gf.tes`
fmt.Println(g.Map{})
fmt.Println(len(s2) >= len(s1) && strings.EqualFold(s2[0 : len(s1)], s1) )
select {}
}

View File

@ -27,10 +27,10 @@ func main() {
</body>
</html>
`, g.Map{
"page1" : g.HTML(page.GetContent(1)),
"page2" : g.HTML(page.GetContent(2)),
"page3" : g.HTML(page.GetContent(3)),
"page4" : g.HTML(page.GetContent(4)),
"page1" : gview.HTML(page.GetContent(1)),
"page2" : gview.HTML(page.GetContent(2)),
"page3" : gview.HTML(page.GetContent(3)),
"page4" : gview.HTML(page.GetContent(4)),
})
r.Response.Write(buffer)
})

View File

@ -33,7 +33,7 @@ func main() {
</body>
</html>
`, g.Map{
"page" : g.HTML(page.GetContent(1)),
"page" : gview.HTML(page.GetContent(1)),
})
r.Response.Write(buffer)
})

View File

@ -38,7 +38,7 @@ func main() {
</body>
</html>
`, g.Map{
"page" : g.HTML(pageContent(page)),
"page" : gview.HTML(pageContent(page)),
})
r.Response.Write(buffer)
})

View File

@ -27,10 +27,10 @@ func main() {
</body>
</html>
`, g.Map{
"page1" : g.HTML(page.GetContent(1)),
"page2" : g.HTML(page.GetContent(2)),
"page3" : g.HTML(page.GetContent(3)),
"page4" : g.HTML(page.GetContent(4)),
"page1" : gview.HTML(page.GetContent(1)),
"page2" : gview.HTML(page.GetContent(2)),
"page3" : gview.HTML(page.GetContent(3)),
"page4" : gview.HTML(page.GetContent(4)),
})
r.Response.Write(buffer)
})