Files
gf/g/database/gdb/gdb.go

229 lines
6.4 KiB
Go
Raw Normal View History

2017-12-29 16:03:30 +08:00
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// 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.
2017-12-31 18:19:58 +08:00
2018-02-28 12:01:14 +08:00
// 数据库ORM操作.
2017-11-23 10:21:28 +08:00
package gdb
import (
"fmt"
"errors"
"database/sql"
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/util/grand"
2017-11-23 10:21:28 +08:00
_ "github.com/lib/pq"
_ "github.com/go-sql-driver/mysql"
2017-11-23 10:21:28 +08:00
)
const (
OPTION_INSERT = 0
OPTION_REPLACE = 1
OPTION_SAVE = 2
OPTION_IGNORE = 3
)
// 数据库操作接口
type Link interface {
2018-03-09 17:55:42 +08:00
// 打开数据库连接,建立数据库操作对象
2017-11-23 10:21:28 +08:00
Open (c *ConfigNode) (*sql.DB, error)
2018-03-09 17:55:42 +08:00
// SQL操作方法
2017-11-23 10:21:28 +08:00
Query(q string, args ...interface{}) (*sql.Rows, error)
Exec(q string, args ...interface{}) (sql.Result, error)
Prepare(q string) (*sql.Stmt, error)
2018-03-09 17:55:42 +08:00
// 数据库查询
2017-12-20 12:05:36 +08:00
GetAll(q string, args ...interface{}) (List, error)
GetOne(q string, args ...interface{}) (Map, error)
2017-11-23 10:21:28 +08:00
GetValue(q string, args ...interface{}) (interface{}, error)
2018-03-09 17:55:42 +08:00
// Ping
2017-11-23 10:21:28 +08:00
PingMaster() error
PingSlave() error
2018-03-09 17:55:42 +08:00
// 连接属性设置
2017-11-23 10:21:28 +08:00
SetMaxIdleConns(n int)
SetMaxOpenConns(n int)
2018-03-09 17:55:42 +08:00
// 开启事务操作
2018-03-12 11:46:12 +08:00
Begin() (*Tx, error)
2017-11-23 10:21:28 +08:00
2018-03-09 17:55:42 +08:00
// 数据表插入/更新/保存操作
2017-12-20 12:05:36 +08:00
Insert(table string, data Map) (sql.Result, error)
Replace(table string, data Map) (sql.Result, error)
Save(table string, data Map) (sql.Result, error)
2017-11-23 10:21:28 +08:00
2018-03-09 17:55:42 +08:00
// 数据表插入/更新/保存操作(批量)
2018-01-08 14:15:46 +08:00
BatchInsert(table string, list List, batch int) (sql.Result, error)
BatchReplace(table string, list List, batch int) (sql.Result, error)
BatchSave(table string, list List, batch int) (sql.Result, error)
2017-11-23 10:21:28 +08:00
2018-03-09 17:55:42 +08:00
// 数据修改/删除
2017-11-23 10:21:28 +08:00
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
2018-03-09 17:55:42 +08:00
// 创建链式操作对象(Table为From的别名)
Table(tables string) (*DbOp)
From(tables string) (*DbOp)
// 关闭数据库操作对象
Close() error
// 内部方法
insert(table string, data Map, option uint8) (sql.Result, error)
batchInsert(table string, list List, batch int, option uint8) (sql.Result, error)
2018-03-12 15:12:38 +08:00
2018-03-09 17:55:42 +08:00
getQuoteCharLeft () string
getQuoteCharRight () string
handleSqlBeforeExec(q *string) *string
2017-11-23 10:21:28 +08:00
}
// 数据库链接对象
2018-03-09 17:55:42 +08:00
type Db struct {
link Link
master *sql.DB
slave *sql.DB
charl string
charr string
2017-11-23 10:21:28 +08:00
}
// 关联数组,绑定一条数据表记录
type Map map[string]interface{}
// 关联数组列表(索引从0开始的数组),绑定多条记录
type List []Map
2018-03-05 17:15:11 +08:00
// 获得默认/指定分组名称的数据库操作对象单例
2018-03-12 15:12:38 +08:00
func Instance (groupName...string) (*Db, error) {
2018-03-05 17:15:11 +08:00
name := config.d
if len(groupName) > 0 {
name = groupName[0]
}
return instance(name)
2017-11-23 10:21:28 +08:00
}
// 根据配置项获取一个数据库操作对象单例
2018-03-12 15:12:38 +08:00
func instance (groupName string) (*Db, error) {
2017-11-23 10:21:28 +08:00
instanceName := "gdb_instance_" + groupName
result := gcache.Get(instanceName)
if result == nil {
2018-03-12 15:12:38 +08:00
db, err := New(groupName)
2017-11-23 10:21:28 +08:00
if err == nil {
2018-03-12 15:12:38 +08:00
gcache.Set(instanceName, db, 0)
return db, nil
2017-11-23 10:21:28 +08:00
} else {
return nil, err
}
} else {
2018-03-12 15:12:38 +08:00
return result.(*Db), nil
2017-11-23 10:21:28 +08:00
}
}
2018-03-05 17:15:11 +08:00
// 使用默认/指定分组配置进行连接数据库集群配置项default
2018-03-12 15:12:38 +08:00
func New(groupName...string) (*Db, error) {
2018-03-05 17:15:11 +08:00
name := config.d
if len(groupName) > 0 {
name = groupName[0]
}
2017-11-23 10:21:28 +08:00
config.RLock()
defer config.RUnlock()
if len(config.c) < 1 {
return nil, errors.New("empty database configuration")
}
2018-03-05 17:15:11 +08:00
if list, ok := config.c[name]; ok {
2017-11-23 10:21:28 +08:00
// 将master, slave集群列表拆分出来
masterList := make(ConfigGroup, 0)
slaveList := make(ConfigGroup, 0)
for i := 0; i < len(list); i++ {
if list[i].Role == "slave" {
slaveList = append(slaveList, list[i])
} else {
// 默认配置项的角色为master
masterList = append(masterList, list[i])
}
}
if len(masterList) < 1 {
return nil, errors.New("at least one master node configuration's need to make sense")
}
2018-04-04 22:46:55 +08:00
2017-11-23 10:21:28 +08:00
masterNode := getConfigNodeByPriority(&masterList)
var slaveNode *ConfigNode
if len(slaveList) > 0 {
slaveNode = getConfigNodeByPriority(&slaveList)
}
2018-03-12 15:12:38 +08:00
return newDb(masterNode, slaveNode)
2017-11-23 10:21:28 +08:00
} else {
2018-03-05 17:15:11 +08:00
return nil, errors.New(fmt.Sprintf("empty database configuration for item name '%s'", name))
2017-11-23 10:21:28 +08:00
}
}
// 根据单点数据库配置获得一个数据库草最对象
2018-03-12 15:12:38 +08:00
func NewByNode(node ConfigNode) (*Db, error) {
return newDb (&node, nil)
2017-11-23 10:21:28 +08:00
}
// 按照负载均衡算法(优先级配置)从数据库集群中选择一个配置节点出来使用
func getConfigNodeByPriority (cg *ConfigGroup) *ConfigNode {
if len(*cg) < 2 {
return &(*cg)[0]
}
var total int
for i := 0; i < len(*cg); i++ {
total += (*cg)[i].Priority * 100
}
r := grand.Rand(0, total)
min := 0
max := 0
for i := 0; i < len(*cg); i++ {
max = min + (*cg)[i].Priority * 100
//fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max)
if r >= min && r < max {
return &(*cg)[i]
} else {
min = max
}
}
return nil
}
// 创建数据库链接对象
2018-03-12 15:12:38 +08:00
func newDb (masterNode *ConfigNode, slaveNode *ConfigNode) (*Db, error) {
2017-11-23 10:21:28 +08:00
var link Link
switch masterNode.Type {
case "mysql":
2018-03-09 17:55:42 +08:00
link = Link(&dbmysql{})
2017-11-23 10:21:28 +08:00
case "pgsql":
2018-03-09 17:55:42 +08:00
link = Link(&dbpgsql{})
2017-11-23 10:21:28 +08:00
default:
return nil, errors.New(fmt.Sprintf("unsupported db type '%s'", masterNode.Type))
}
master, err := link.Open(masterNode)
if err != nil {
2018-03-12 15:12:38 +08:00
return nil, err
2017-11-23 10:21:28 +08:00
}
slave := master
if slaveNode != nil {
slave, err = link.Open(slaveNode)
if err != nil {
2018-03-12 15:12:38 +08:00
return nil, err
2017-11-23 10:21:28 +08:00
}
}
2018-03-12 15:12:38 +08:00
//link.setLink(link)
//link.setMaster(master)
//link.setSlave(slave)
//link.setQuoteChar(link.getQuoteCharLeft(), link.getQuoteCharRight())
return &Db {
link : link,
master : master,
slave : slave,
charl : link.getQuoteCharLeft(),
charr : link.getQuoteCharRight(),
}, nil
2017-11-23 10:21:28 +08:00
}