【问题标题】:Using a singleton database class with separate models and services packages使用具有单独模型和服务包的单例数据库类
【发布时间】:2018-03-24 05:15:08
【问题描述】:

我的问题类似于How to create singleton DB class in GoLang,但我无法让它与单独的模型和服务包一起使用。

项目/lib/database/mysql.go:

package database

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

type Manager struct {
    *gorm.DB
}

var Mgr *Manager

func init() {
    dsn := MysqlConnectionString("parseTime=true")
    tablePrefix := "demo"
    var err error

    gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
        return fmt.Sprintf("%v_%v", tablePrefix, defaultTableName)
    }

    db, err := gorm.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }

    Mgr = &Manager{db}
}

project/lib/models/retailer_keys.go

package models

import (
    "fmt"
    "project/lib/database"
    "time"
)

type RetailerKeysInterface interface {
    RetailerKeys() ([]*RetailerKey, error)
}

type DB struct {
    database.Manager
}

type RetailerKey struct {
    Id         int        `json:"id"`
    RetailerId int        `json:"retailer_id"`
    Key        string     `json:"key"`
    Enabled    *bool      `json:"enabled"`
    CreatedAt  *time.Time `json:"created_at"`
    UpdatedAt  *time.Time `json:"updated_at"`
}

func (db *DB) RetailerKeys() ([]*RetailerKey, error) {
    var keys []*RetailerKey
    if err := db.Find(&keys).Error; err != nil {
        return nil, err
    }
    return keys, nil
}

project/lib/services/retailer_keys.go

import (
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/apigateway"
    "gopkg.in/volatiletech/null.v6"

    "project/lib/models"
    "project/lib/services/api_keys"
)

func GetKeys() ([]*models.RetailerKey, error) {
    var q models.RetailerKeysInterface

    keys, err := q.RetailerKeys()
    if err != nil {
        return nil, err
    }
    return keys, nil
}

func CreateKey(id int) (models.RetailerKey, error) {
    ...
}

然后可以在我的主包中使用它,例如:

package main

import (
    "context"
    "encoding/json"
    // "reflect"
    "fmt"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"

    _ "project/lib/config"
    "project/lib/services"
)

func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    statusCode := 200

    keys, err := services.GetKeys()
    if err != nil {
        statusCode = 400
    }
    body, _ := json.Marshal(keys)

    return events.APIGatewayProxyResponse{
        Body:       string(body),
        StatusCode: statusCode,
    }, nil
}

...

我希望能够在我的模型中嵌入 Manager 类型的相关子集。

编辑: 根据 cmets 中的反馈编辑问题/代码。

这给了我一个错误:runtime error: invalid memory address or nil pointer dereference

【问题讨论】:

  • 根据引用的代码,错误是准确的; DB 没有 Find 方法。有什么问题?
  • @Adrian 然后我如何访问模型包中的 *gorm.DB?
  • type Manager interface {} 没有定义任何方法,将其嵌入DB 不会神奇地揭示 gorm 的方法。您需要定义要在 Manager 上使用的 gorm 方法,或者不使用接口并将 gorm.DB 嵌入到您的数据库中。
  • 尝试浏览这些:onetwothreefour。在这里你可以看到哪里出了问题:play.golang.org/p/yjwMLHToNP9 还要注意堆栈跟踪中的行号,它们会告诉你你到底在哪里犯了错误。

标签: go


【解决方案1】:

我肯定误解了 go 中的接口。在完成 A Tour of Go 之后,它开始变得更加清晰。

这就是我最终为正在经历同样事情的任何人所做的事情。我将保留最初的问题,以便您查看差异。

项目/lib/database/mysql.go:

package database

import (
    "fmt"
    "log"

    _ "github.com/go-sql-driver/mysql" // Needed for gorm
    "github.com/jinzhu/gorm"
)

var Manager *gorm.DB

func init() {
    var err error

    dsn := MysqlConnectionString("parseTime=true")
    tablePrefix := "qcommerce"

    gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
        return fmt.Sprintf("%v_%v", tablePrefix, defaultTableName)
    }

    Manager, err = gorm.Open("mysql", dsn)
    if err != nil {
        log.Fatal(err)
    }

    if err := Manager.DB().Ping(); err != nil {
        log.Fatal(err)
    }
}

project/lib/models/retailer_keys.go

package models

import (
    "project/lib/database"
    "time"
)

type QRetailerKeys interface {
    Insert() error
    Find() error
}

type RetailerKey struct {
    ID                  int        `json:"id"`
    RetailerID          int        `json:"retailer_id"`
    Retailer            Retailer   `json:"retailer"`
    Key                 string     `json:"key"`
    Enabled             bool       `json:"enabled" gorm:"DEFAULT:true"`
    CreatedAt           *time.Time `json:"created_at"`
    UpdatedAt           *time.Time `json:"updated_at"`
}

// RetailerKeys returns a slice of all keys in table
func RetailerKeys() ([]*RetailerKey, error) {
    var keys []*RetailerKey
    if err := database.Manager.Find(&keys).Error; err != nil {
        return nil, err
    }
    return keys, nil
}

func (r *RetailerKey) Find() error {
    ...
}

// Create a new key
func (r *RetailerKey) Create() error {
    return database.Manager.Create(&r).Error
}

project/lib/services/retailer_keys.go

package services

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    // "github.com/aws/aws-sdk-go/service/apigateway"

    "partners.drinks.com/lib/models"
    "partners.drinks.com/lib/services/api_keys"
)

func sessionBuilder() *session.Session {
    config := &aws.Config{
        Region: aws.String("us-west-2"),
    }
    session := session.Must(session.NewSession(config))
    return session
}

func GetKeys() ([]*models.RetailerKey, error) {
    keys, err := models.RetailerKeys()
    if err != nil {
        return nil, err
    }
    return keys, nil
}

func CreateKey(id int) (models.RetailerKey, error) {
    apikeys := &api_keys.ApiKeyBuilder{}
    base64Key := apikeys.GenUUID().GenKey().Base64

    var key = models.RetailerKey{
        RetailerID: id,
        Key: base64Key,
        Enabled: func(b bool)
    }

    if err := key.Create(); err != nil {
        return models.RetailerKey{}, err
    }
    ...

    return key, nil
}

我是这样使用的:

package main

import (
    "context"
    "encoding/json"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"

    _ "partners.drinks.com/lib/config"
    "partners.drinks.com/lib/services"
)


func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    statusCode := 200

    keys, err := services.GetKeys()
    if err != nil {
        statusCode = 400
    }
    body, _ := json.Marshal(keys)

    return events.APIGatewayProxyResponse{
        Body:       string(body),
        StatusCode: statusCode,
    }, nil
}

...

感谢 @mkopriva 提供 cmets 中的链接资源。

【讨论】:

    猜你喜欢
    • 2019-09-13
    • 2011-01-22
    • 2015-11-30
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多