Как вызвать метод CRUD mongoDB из обработчика?

Я написал простой пакет MongoDB с некоторыми методами CRUD:

package backend

import "labix.org/v2/mgo"

type MongoDBConn struct {
    session *mgo.Session
}

type ToDo struct {
    Title       string
    Description string
}

func NewMongoDBConn() *MongoDBConn {
    return &MongoDBConn{}
}

func (m *MongoDBConn) Connect(url string) *mgo.Session {
    session, err := mgo.Dial(url)
    if err != nil {
        panic(err)
    }
    m.session = session
    return m.session
}

func (m *MongoDBConn) Stop() {
    m.session.Close()
}

func (m *MongoDBConn) AddToDo(title, description string) (err error) {
    c := m.session.DB("test").C("people")
    err = c.Insert(&ToDo{title, description})
    if err != nil {
        panic(err)
    }
    return nil
}

У меня есть server.go, где я создаю Http-сервер и имею обработчики для разных URL-адресов. Я хотел бы иметь возможность подключаться к MongoDB и вызывать метод AddToDo в определенном обработчике. Я могу подключиться к БД из основного метода моего сервера:

import (
    "./backend"
       //other boilerplate imports
)

func AddHandler(writer http.ResponseWriter, request *http.Request) {
    log.Printf("serving %v %v", request.Method, request.URL.Path[1:])
    if request.Method != "POST" {
        serve404(writer)
        return
    }
    title := request.FormValue("title")
    description := request.FormValue("description")
    fmt.Fprintf(writer, " title description %v %v", title, description)
//I can't call mongoConn.AddToDo(title, description) from here

}    
func main() {
        //connect to mongoDB
        mongoConn := backend.NewMongoDBConn()
        _ = mongoConn.Connect("localhost")
        defer mongoConn.Stop()
    }

Но я не уверен, как вызвать метод mongoConn.AddToDo(title, description string) из обработчика. Должен ли я создать глобальную переменную подключения к базе данных?


person jwesonga    schedule 24.12.2012    source источник


Ответы (2)


Два простых метода:

1.сеанс глобальной базы данных

package main


import (
    "net/http"
    "log"
    "fmt"
    "./backend"
)


var mongoConn * backend.MongoDBConn

func AddHandler(w http.ResponseWriter, r *http.Request) {
    log.Printf("serving %v %v", r.Method, r.URL.Path[1:])
    if r.Method != "POST" {
        fmt.Fprintln(w, "Not POST Method ")
        return
    }
    title := r.FormValue("title")
    description := r.FormValue("description")



    fmt.Fprintf(w, " title description %v %v", title, description)
//I can't call mongoConn.AddToDo(title, description) from here
    mongoConn.AddToDo(title, description)
}    

const AddForm = `
<html><body>
<form method="POST" action="/add">
Name: <input type="text" name="title">
Age: <input type="text" name="description">
<input type="submit" value="Add">
</form>
</body></html>
`
func Index(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, AddForm)
}

func main() {
        //connect to mongoDB


       mongoConn = backend.NewMongoDBConn()
        _ = mongoConn.Connect("localhost")
        defer mongoConn.Stop()

        http.HandleFunc("/", Index)
        http.HandleFunc("/add", AddHandler)

        log.Println("Start Server:")
        err := http.ListenAndServe(":8080", nil)

        if err != nil {
            log.Fatal("ListenAndServe:", err)
        }
}

2.новое подключение к БД при каждом запросе

import (
    "./backend"
       //other boilerplate imports
)

func AddHandler(writer http.ResponseWriter, request *http.Request) {
    log.Printf("serving %v %v", request.Method, request.URL.Path[1:])
    if request.Method != "POST" {
        serve404(writer)
        return
    }
    title := request.FormValue("title")
    description := request.FormValue("description")
    fmt.Fprintf(writer, " title description %v %v", title, description)
    //................
    mongoConn := backend.NewMongoDBConn()
    _ = mongoConn.Connect("localhost")
    mongoConn.AddToDo(title, description)
    //....................
    mongoConn.Stop()

} 

......

лучшее решение:

Вы можете создать пул сеансов БД, а затем перед обработкой запроса выбрать один и поместить в контекст этого запроса. Затем, после выполнения запроса, вы отправляете соединение обратно в пул.

Если пул пуст, вы создаете новое соединение. Если пул заполнен, вы закрываете соединение.

Для получения дополнительной информации нажмите здесь.

person pexeer    schedule 24.12.2012
comment
Первое решение глобальной переменной, пробовал раньше, не работает. Я продолжаю получать эту ошибку: http: паническое обслуживание [::1]:55642: ошибка времени выполнения: неверный адрес памяти или разыменование нулевого указателя - person jwesonga; 24.12.2012
comment
определить глобальную переменную: var mongoConn *benkend.MongoDBConn, подключить mongodb к основной функции: mongoConn = backend.NewMongoDBConn(). Я изменил код выше, он работает. - person pexeer; 25.12.2012
comment
Нет смысла создавать пул сеансов БД. mgo будет внутренне кэшировать ресурсы при закрытии сеанса и будет повторно использовать эти ресурсы при создании нового сеанса. - person Gustavo Niemeyer; 13.01.2014

Да, глобальная сессия — это простой способ справиться с этим. Затем в верхней части каждого обработчика вы можете сделать что-то вроде:

func handler(...) {
    session := globalSession.Copy()
    defer session.Close()
}

так что каждый обработчик получает свою собственную сессию для работы.

Обратите внимание, что копирование и закрытие сеансов являются дешевыми операциями, которые внутренне будут работать с пулом соединений, а не устанавливать новые соединения для каждого созданного сеанса.

person Gustavo Niemeyer    schedule 13.01.2014
comment
Прежде всего спасибо за ответы на эти вопросы. Как основной разработчик mgo особо авторитетен. Я смотрю на код в mgo/session.go, Apply(), например, уже клонирует сеанс, так зачем нужно создавать копии глобального сеанса самостоятельно? - person Bernard; 23.12.2014