package main
import (
"errors"
"fmt"
"github.com/gohouse/gorose"
"sync"
"time"
)
//頻繁的創建和關閉連接,對系統會造成很大負擔
//所以我們需要一個池子,里面事先創建好固定數量的連接資源,需要時就取,不需要就放回池中。
//但是連接資源有一個特點,我們無法保證連接長時間會有效。
//比如,網路原因,人為原因等都會導致連接失效。
//所以我們設定一個超時時間,如果連接時間與當前時間相差超過超時時間,那么就關閉連接。
type Factory struct {
conn *gorose.Connection
err error
}
func (factory *Factory)Close(){
factory.conn.Close()
}
func (factory *Factory)factory()(conn *gorose.Connection,err error){
return factory.conn,factory.err
}
//工廠方法,用于創建連接資源
func NewConn()(factory Factory){
var dbConfig = &gorose.DbConfigSingle{
Driver: "mysql", // driver: mysql/sqlite/oracle/mssql/postgres
EnableQueryLog: true, // if enable sql logs
SetMaxOpenConns: 0, // connection pool of max Open connections, default zero
SetMaxIdleConns: 0, // connection pool of max sleep connections
Prefix: "", // prefix of table
Dsn: "root:root@tcp(localhost:3306)/test?charset=utf8", // db dsn
}
// 初始化資料庫鏈接, 默認會鏈接配置中 default 指定的值
// 也可以在第二個引數中指定對應的資料庫鏈接, 見下邊注釋的那一行鏈接示例
connection, err :=gorose.Open(dbConfig )
return Factory{connection,err}
}
//連接
type Conn struct {
conn *gorose.Connection
//連接時間
time time.Time
}
//連接池
type ConnPool struct {
//互斥鎖,保證資源安全
mu sync.Mutex
//通道,保存所有連接資源
conns chan *Conn
//工廠方法,創建連接資源
factory Factory
//判斷池是否關閉
closed bool
//連接超時時間
connTimeOut time.Duration
}
//創建一個連接資源池
func NewConnPool(factory Factory, cap int, connTimeOut time.Duration) (*ConnPool, error) {
if cap <= 0 {
return nil, errors.New("cap不能小于0")
}
if connTimeOut <= 0 {
return nil, errors.New("connTimeOut不能小于0")
}
cp := &ConnPool{
mu: sync.Mutex{},
conns: make(chan *Conn, cap),
factory: factory,
closed: false,
connTimeOut: connTimeOut,
}
for i := 0; i < cap; i++ {
//通過工廠方法創建連接資源
newConn:=NewConn()
conn1, err := newConn.factory()
if err != nil {
cp.Close()
return nil, errors.New("factory出錯")
}
//將連接資源插入通道中
cp.conns <- &Conn{conn: conn1, time: time.Now()}
}
return cp, nil
}
//獲取連接資源
func (cp *ConnPool) Get() (*gorose.Connection, error) {
if cp.closed {
return nil, errors.New("連接池已關閉")
}
for {
select {
//從通道中獲取連接資源
case connRes, ok := <-cp.conns:
{
if !ok {
return nil, errors.New("連接池已關閉")
}
//判斷連接中的時間,如果超時,則關閉
//繼續獲取
if time.Now().Sub(connRes.time) > cp.connTimeOut {
connRes.conn.Close()
continue
}
return connRes.conn, nil
}
default:
{
//如果無法從通道中獲取資源,則重新創建一個資源回傳
newConn:=NewConn()
connRes, err := newConn.factory()
if err != nil {
return nil, err
}
return connRes, nil
}
}
}
}
//連接資源放回池中
func (cp *ConnPool) Put(conn *gorose.Connection) error {
if cp.closed {
return errors.New("連接池已關閉")
}
select {
//向通道中加入連接資源
case cp.conns <- &Conn{conn: conn, time: time.Now()}:
{
return nil
}
default:
{
//如果無法加入,則關閉連接
conn.Close()
return errors.New("連接池已滿")
}
}
}
//關閉連接池
func (cp *ConnPool) Close() {
if cp.closed {
return
}
cp.mu.Lock()
cp.closed = true
//關閉通道
close(cp.conns)
//回圈關閉通道中的連接
for conn := range cp.conns {
conn.conn.Close()
}
cp.mu.Unlock()
}
//回傳池中通道的長度
func (cp *ConnPool) len() int {
return len(cp.conns)
}
func main() {
cp, _ := NewConnPool(NewConn(), 10, time.Second*10)
//獲取資源
conn1, _ := cp.Get()
conn2, _ := cp.Get()
//這里連接池中資源大小為8
fmt.Println("cp len : ", cp.len())
//var session *gorose.Connection
session:= conn1.NewSession()
res,err := session.Table("users").First()
if err!=nil{
fmt.Println("db.Table",err)
return
}
fmt.Println(res)
//把2個連接資源放回池中
cp.Put(conn1)
cp.Put(conn2)
//這里顯示為3
fmt.Println("cp len : ", cp.len())
cp.Close()
}
uj5u.com熱心網友回復:
http和sql都自帶連接池uj5u.com熱心網友回復:
sql庫自帶連接池吧……uj5u.com熱心網友回復:
http和sql都自帶連接池uj5u.com熱心網友回復:
連接池不是問題,最大的問題是連接如何跟當前背景關系系結,也就是類似于java中執行緒跟連接系結,保證當前多次操作資料庫都是同一個連接轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/75069.html
標籤:其他技術討論專區
上一篇:服務器上有兩個專案,第一個修改其他tomcat埠都能訪問,第二個修改別的埠不能訪問
下一篇:登錄測驗用例最全場景
