GO 语言我想在mian 函数中实现链接池,我需要这么实现呢!

    runtime.GOMAXPROCS(runtime.NumCPU());    
    // var redisAddress string
    // redisAddress="127.0.0.1:6379"
    // defer c.Close()
    //默认使用5号DB  存储session
    //[code]  这里实现数据库和redis 的链接池
    
    
    //[code] end
    // v :=  daocore.InitRedis("tcp",redisAddress)
    http.HandleFunc("/login/login", handler.Apply)
    http.ListenAndServe(":8666", nil)

可以在 handler.Apply 中调用的。

阅读 2.7k
3 个回答

如果说你实际想知道的是怎么实现一个连接池组件,那我也没有更多经验可说的。但假如你是想问,如何在HTTP Handler里面通过连接池获取到连接,然后拿连接去处理具体业务的话,我还可以说两句:概括起来就是,server在启动时实例化连接池,在每次处理http请求的实际业务前,把连接池的指针或者一个连接放到requestcontext中,那么,在实际的业务处理前,就可以从context中拿到连接。这种机制很常见,有的叫中间件,有的叫拦截器

对于连接池,有很多现成的包可以用。
这里推荐一个我自己觉得挺不错的库:
https://github.com/silenceper...
我自己也基于这个库实现了一个grpc的连接池库,扩展性也很强。建议参考一下他的实现。

我造了一些轮子:https://github.com/hunterhug/... 给你贴一个代码:

  1. Redis:

/*
Copyright 2017 by GoSpider author.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package myredis

import (
    "errors"
    "github.com/hunterhug/GoSpider/util"
    "gopkg.in/redis.v4"
    "time"
)

// redis tool

type RedisConfig struct {
    Host     string
    Password string
    DB       int
}

type MyRedis struct {
    Config RedisConfig
    Client *redis.Client
}

// return myredis
func NewRedis(config RedisConfig) (*MyRedis, error) {
    myredis := &MyRedis{Config: config}
    client := redis.NewClient(&redis.Options{
        Addr:        config.Host,
        Password:    config.Password, // no password set
        DB:          config.DB,       // use default DB
        MaxRetries:  5,               // fail command retry 2
        PoolSize:    40,              // redis pool size
        DialTimeout: util.Second(20),
        // another options is default
    })

    pong, err := client.Ping().Result()
    if err == nil && pong == "PONG" {
        myredis.Client = client
    }
    return myredis, err
}

func NewRedisPool(config RedisConfig, size int) (*MyRedis, error) {
    myredis := &MyRedis{Config: config}
    client := redis.NewClient(&redis.Options{
        Addr:        config.Host,
        Password:    config.Password, // no password set
        DB:          config.DB,       // use default DB
        MaxRetries:  5,               // fail command retry 2
        PoolSize:    size,            // redis pool size
        DialTimeout: util.Second(20),
        // another options is default
    })

    pong, err := client.Ping().Result()
    if err == nil && pong == "PONG" {
        myredis.Client = client
    }
    return myredis, err
}

// set key
func (db *MyRedis) Set(key string, value string, expire time.Duration) error {
    return db.Client.Set(key, value, expire).Err()
}

// get key
func (db *MyRedis) Get(key string) (string, error) {
    result, err := db.Client.Get(key).Result()
    if err == redis.Nil {
        return "", errors.New("redis key does not exists")
    } else if err != nil {
        return "", err
    } else {
        return result, err
    }
}

func (db *MyRedis) Lpush(key string, values ...interface{}) (int64, error) {
    return db.Client.LPush(key, values...).Result()
}

func (db *MyRedis) Lpushx(key string, values interface{}) (int64, error) {
    num, err := db.Client.LPushX(key, values).Result()
    if err != nil {
        return 0, err
    }
    if num == 0 {
        return 0, errors.New("Redis List not exist")
    } else {
        return num, err
    }
}

func (db *MyRedis) Rpush(key string, values ...interface{}) (int64, error) {
    return db.Client.RPush(key, values...).Result()
}

func (db *MyRedis) Rpushx(key string, values interface{}) (int64, error) {
    num, err := db.Client.RPushX(key, values).Result()
    if err != nil {
        return 0, err
    }
    if num == 0 {
        return 0, errors.New("Redis List not exist")
    } else {
        return num, err
    }
}

func (db *MyRedis) Llen(key string) (int64, error) {
    return db.Client.LLen(key).Result()
}

func (db *MyRedis) Hlen(key string) (int64, error) {
    return db.Client.HLen(key).Result()
}

func (db *MyRedis) Rpop(key string) (string, error) {
    return db.Client.RPop(key).Result()
}

func (db *MyRedis) Lpop(key string) (string, error) {
    return db.Client.LPop(key).Result()
}

func (db *MyRedis) Brpop(timeout int, keys ...string) ([]string, error) {
    timeouts := time.Duration(timeout) * time.Second
    return db.Client.BRPop(timeouts, keys...).Result()
}

// if timeout is zero will be block until...
// and if  keys has many will return one such as []string{"pool","b"},pool is list,b is value
func (db *MyRedis) Blpop(timeout int, keys ...string) ([]string, error) {
    timeouts := time.Duration(timeout) * time.Second
    return db.Client.BLPop(timeouts, keys...).Result()
}

func (db *MyRedis) Brpoplpush(source, destination string, timeout int) (string, error) {
    timeouts := time.Duration(timeout) * time.Second
    return db.Client.BRPopLPush(source, destination, timeouts).Result()
}

func (db *MyRedis) Rpoplpush(source, destination string) (string, error) {
    return db.Client.RPopLPush(source, destination).Result()
}

func (db *MyRedis) Hexists(key, field string) (bool, error) {
    return db.Client.HExists(key, field).Result()
}

func (db *MyRedis) Hget(key, field string) (string, error) {
    return db.Client.HGet(key, field).Result()
}

func (db *MyRedis) Hset(key, field, value string) (bool, error) {
    return db.Client.HSet(key, field, value).Result()
}

// return item rem number if count==0 all rem if count>0 from the list head to rem
func (db *MyRedis) Lrem(key string, count int64, value interface{}) (int64, error) {
    return db.Client.LRem(key, count, value).Result()
}

2.MYSQL

/*
Copyright 2017 by GoSpider author.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mysql

// 数据库CURD,需要写SQL语句调用,简单就是美
import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    log "github.com/hunterhug/GoSpider/store"
)

// Mysql config
type MysqlConfig struct {
    Username string
    Password string
    Ip       string
    Port     string
    Dbname   string
}

// a client
type Mysql struct {
    Config MysqlConfig
    Client *sql.DB
}

func New(config MysqlConfig) *Mysql {
    return &Mysql{Config: config}
}

//插入数据
//Insert Data
func (db *Mysql) Insert(prestring string, parm ...interface{}) (int64, error) {
    stmt, err := db.Client.Prepare(prestring)
    if err != nil {
        return 0, err
    }
    R, err := stmt.Exec(parm...)
    if err != nil {
        return 0, err
    }
    defer stmt.Close()
    num, err := R.RowsAffected()
    return num, err

}

// 建表
// Create table
func (db *Mysql) Create(prestring string, parm ...interface{}) (int64, error) {
    stmt, err := db.Client.Prepare(prestring)
    if err != nil {
        return 0, err
    }
    R, err := stmt.Exec(parm...)
    if err != nil {
        return 0, err
    }
    defer stmt.Close()
    num, err := R.RowsAffected()
    return num, err

}

// 删表
func (db *Mysql) Drop(prestring string, parm ...interface{}) (int64, error) {
    stmt, err := db.Client.Prepare(prestring)
    if err != nil {
        return 0, err
    }
    R, err := stmt.Exec(parm...)
    if err != nil {
        return 0, err
    }
    defer stmt.Close()
    num, err := R.RowsAffected()
    return num, err

}

// create database
func (dbconfig MysqlConfig) CreateDb() error {
    dbname := dbconfig.Dbname
    sql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;", dbname)
    dbconfig.Dbname = ""
    db := New(dbconfig)
    db.Open(30, 0)
    _, err := db.Create(sql)
    dbconfig.Dbname = dbname
    return err

}

func (dbconfig MysqlConfig) DeleteDb() error {
    dbname := dbconfig.Dbname
    sql := fmt.Sprintf("DROP DATABASE IF EXISTS `%s`;", dbname)
    dbconfig.Dbname = ""
    db := New(dbconfig)
    db.Open(30, 0)
    _, err := db.Create(sql)
    dbconfig.Dbname = dbname
    return err
}

//打开数据库连接 open a connecttion
//username:password@protocol(address)/dbname?param=value
func (db *Mysql) Open(maxopen int, maxidle int) {
    if db.Client != nil {
        return
    }
    dbs, err := sql.Open("mysql", db.Config.Username+":"+db.Config.Password+"@tcp("+db.Config.Ip+":"+db.Config.Port+")/"+db.Config.Dbname+"?charset=utf8")
    if err != nil {
        log.Logger.Fatalf("Open database error: %s", err.Error())
    }
    //defer dbs.Close()
    dbs.SetMaxIdleConns(maxidle)
    dbs.SetMaxOpenConns(maxopen)

    err = dbs.Ping()
    if err != nil {
        log.Logger.Fatalf("Ping err:%s", err.Error())
    }

    db.Client = dbs
}

//查询数据库 Query
func (db *Mysql) Select(prestring string, parm ...interface{}) (returnrows []map[string]interface{}, err error) {
    returnrows = []map[string]interface{}{}
    rows, err := db.Client.Query(prestring, parm...)
    if err != nil {
        return
    }

    defer rows.Close()
    // Get column names
    columns, err := rows.Columns()

    if err != nil {
        return nil, err
    }

    // Make a slice for the values
    values := make([]sql.RawBytes, len(columns))

    // rows.Scan wants '[]interface{}' as an argument, so we must copy the
    // references into such a slice
    // See http://code.google.com/p/go-wiki/wiki/InterfaceSlice for details
    scanArgs := make([]interface{}, len(values))
    for i := range values {
        scanArgs[i] = &values[i]
    }

    // Fetch rows
    for rows.Next() {
        returnrow := map[string]interface{}{}
        // get RawBytes from data
        err = rows.Scan(scanArgs...)
        if err != nil {
            return nil, err
        }

        // Now do something with the data.
        // Here we just print each column as a string.
        var value string
        for i, col := range values {
            // Here we can check if the value is nil (NULL value)
            if col == nil {
                value = "NULL"
            } else {
                value = string(col)
            }
            returnrow[columns[i]] = value

        }
        returnrows = append(returnrows, returnrow)
    }
    if err = rows.Err(); err != nil {
        return nil, err
    }
    return
}

至于池嘛....

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题