2015-05-04 2 views
0

Новинка отсюда. Приходите из .Net-земли, так что несите меня ... Хотелось бы получить некоторое руководство по архитектуре моего приложения Go специально в отношении управления и повторного использования соединений с БД.GoLang: Losing scope в базе данных

Я разделил свой код db на пакет, чтобы позволить db-lookups в пакете обрабатывать SQL-запросы, подобные слою репозитория. Я хочу иметь гибкость, чтобы отделить мой уровень db от моих сервисов приложений, поэтому я могу легко заменить мою базу данных, если это необходимо.

В основном я ищу несколько советов о том, как и когда обрабатывать sql connect и удерживать указатель sql.DB в приложении. Нужно ли удерживать глобальный указатель в main.go или я могу управлять соединением в моем пакете mysql?

Вот мой код:

package mysqlstorage 

import (
    "database/sql" 
    "fmt" 
    "log" 
    "types" 
) 

var db *sql.DB 

func Connect() { 
    db, dberr := sql.Open(“<CONNECTION_STRING>“) 

    if dberr != nil { 
     fmt.Println(dberr) 
    } 
} 

func SaveUser(u types.User) { 
    // use db here! 
    .... 
} 

func GetUser(id string) types.User { 
    // use db here! 
    .... 
} 

На мой main.go работает и с помощью моего пакета userservices, чтобы попытаться сохранить пользователя, я попал в проблему, когда я появляюсь потерять сферу моего указателя: -

2015/05/03 17:49:08 http: panic serving [::1]:50106: runtime error: invalid memory address or nil pointer dereference goroutine 7 [running]: net/http.func·011() 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1130 +0xbb database/sql.(*DB).conn(0x0, 0x10, 0x0, 0x0) 
/usr/local/Cellar/go/1.4.2/libexec/src/database/sql/sql.go:634 +0x7ae database/sql.(*DB).Ping(0x0, 0x0, 0x0)  
/usr/local/Cellar/go/1.4.2/libexec/src/database/sql/sql.go:462 +0x3a mysqlstorage.SaveUser(0x0, 0xc20805425a, 0x7, 0xc208054280, 0x11, 0xc208054268, 0x6, 0xc208054274, 0x5)  
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/mysqlstorage/mysqlstorage.go:24 
    +0x35 services.CreateUser(0x57c148, 0xc2080563c0, 0xc2080329c0)  
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/services/userservices.go:30 
    +0x398 net/http.HandlerFunc.ServeHTTP(0x3d02a0, 0x57c148, 0xc2080563c0, 0xc2080329c0) 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1265 +0x41 github.com/gorilla/mux.(*Router).ServeHTTP(0xc20803c140, 0x57c148, 0xc2080563c0, 0xc2080329c0)  
/Users/<USERNAME>/Desktop/go/<APPNAME>/api/src/github.com/gorilla/mux/mux.go:98 
    +0x297 net/http.(*ServeMux).ServeHTTP(0xc20803a720, 0x57c148, 0xc2080563c0, 0xc2080329c0) 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1541 +0x17d net/http.serverHandler.ServeHTTP(0xc2080543c0, 0x57c148, 0xc2080563c0, 0xc2080329c0) 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1703 +0x19a net/http.(*conn).serve(0xc208056320) 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1204 +0xb57 created by net/http.(*Server).Serve 
/usr/local/Cellar/go/1.4.2/libexec/src/net/http/server.go:1751 +0x35e 

Любое руководство будет оценено! Спасибо, парни!

+0

'db, dberr = ...' и сделать 'dberr' глобальной переменной? – semicircle21

+0

См. Соответствующую [Определение глобальной переменной и короткой переменной] (https://stackoverflow.com/questions/28284138/go-global-variable-and-short-variable-definition) –

+0

Спасибо, ребята, yup .. обрабатывая переменные глобально это то, к чему я должен привыкнуть, чтобы избежать многих лет! Благодаря! – freya19

ответ

3

Я думаю, что ваша проблема в том, что db в Connect() объеме является shadowed вследствие использования вами оператора :=. Если вы изменили метод объявить dberr вар:

func Connect() { 
    var dberr error 
    db, dberr = sql.Open(“<CONNECTION_STRING>“) 

    if dberr != nil { 
     fmt.Println(dberr) 
    } 
} 

Ваш код будет работать как задумано

+0

Да, это работает благодаря Ландеру. Я обязательно позабочусь о сфере применения! – freya19

+0

@ freya19 Рад слышать! Также ознакомьтесь с документом [Effective Go] (https://golang.org/doc/effective_go.html), который может помочь вам немного в вашем процессе разработки (например, с помощью функции func (u * types.User) Save() 'поэтому вы можете вызывать' user.Save() 'вместо' SaveUser (user) '). – Lander

+0

Спасибо, Ландер! Вы проверите это. Спасибо за предложение. – freya19

2

Как отметил @Lander ваш вне сферы происходит потому, что вы создаете локальную БД переменную через db, err :=, которое затем выходит из области действия, когда возвращается функция Connect func.

В общем случае на использовании sql.DB

От database/sql package:

БД представляет собой базу данных дескриптор, представляющий пул из нуля или более основных соединений. Это безопасно для одновременного использования несколькими goroutines.

Пакет sql создает и освобождает соединения автоматически; он также поддерживает свободный пул простоя соединений.

и

Возвращенный DB является безопасным для одновременного использования нескольких goroutines и поддерживает свой собственный пул бездействующих соединений. Таким образом, функцию Open следует вызывать только один раз. Крайне редко необходимо закрыть БД.

Это означает, что вы хотите открыть соединение один раз, а затем держать его открытым в течение всего процесса. При этом единственный надежный способ фактически закрыть его, когда вы закончите (или напасть на фатальную или панику), - это сделать идиоматический переход defer db.Close() сразу после его открытия, что необходимо будет сделать в основной функции.

Вы все равно можете сохранить свою функцию Connect в своем пакете, а также использовать ее для инициализации глобальной переменной пакета db, но назовите ее из основного и возвратите * sql.DB, чтобы вы могли отложить db.Close().

+0

Удивительный, спасибо IamNaN. Я буду осторожен в том, чтобы передавать соединения и использовать отсрочку, если я правильно их использую. :) – freya19

Смежные вопросы