第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

Golang 事務(wù)性 API 設(shè)計(jì)

Golang 事務(wù)性 API 設(shè)計(jì)

Go
蝴蝶刀刀 2023-03-21 15:57:35
我正在嘗試使用 Go 遵循Clean Architecture。該應(yīng)用程序是一個(gè)簡(jiǎn)單的圖像管理應(yīng)用程序。我想知道如何最好地為我的存儲(chǔ)庫(kù)層設(shè)計(jì)接口。我不想將所有存儲(chǔ)庫(kù)方法組合到一個(gè)大接口中,就像我發(fā)現(xiàn)的一些示例那樣,我認(rèn)為在 Go 中通常首選小接口。我不認(rèn)為有關(guān)管理圖像的用例代碼需要知道存儲(chǔ)庫(kù)還存儲(chǔ)用戶。所以我想有UserReader,UserWriter和ImageReader。ImageWriter復(fù)雜的是代碼需要是事務(wù)性的。事務(wù)管理屬于 Clean Architecture 存在一些爭(zhēng)論,但我認(rèn)為用例層需要能夠控制事務(wù)。我認(rèn)為,屬于單個(gè)事務(wù)的是業(yè)務(wù)規(guī)則,而不是技術(shù)細(xì)節(jié)?,F(xiàn)在的問題是,如何構(gòu)造接口?功能方法所以在這種方法中,我打開一個(gè)事務(wù),運(yùn)行提供的函數(shù)并在沒有錯(cuò)誤的情況下提交。type UserRepository interface {    func ReadTransaction(txFn func (UserReader) error) error    func WriteTransaction(txFn func (UserWriter) error) error}type ImageRepository interface {    func ReadTransaction(txFn func (ImageReader) error) error    func WriteTransaction(txFn func (ImageWriter) error) error}問題:不,我不能在單個(gè)事務(wù)中輕松地編寫用戶和圖像,我必須UserImageRepository為此創(chuàng)建一個(gè)額外的接口并提供一個(gè)單獨(dú)的實(shí)現(xiàn)。事務(wù)作為存儲(chǔ)庫(kù)type ImageRepository interface {    func Writer() ImageReadWriter    func Reader() ImageReader}我認(rèn)為這與功能方法非常相似。它不會(huì)解決聯(lián)合使用多個(gè)存儲(chǔ)庫(kù)的問題,但至少可以通過編寫一個(gè)簡(jiǎn)單的包裝器來實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)可能是這樣的:type BoltDBRepository struct {}type BoltDBTransaction struct { *bolt.Tx }func (tx *BoltDBTransaction) WriteImage(i usecase.Image) errorfunc (tx *BoltDBTransaction) WriteUser(i usecase.User) error....不幸的是,如果我實(shí)現(xiàn)這樣的交易方法:func (r *BoltDBRepository) Writer() *BoltDBTransactionfunc (r *BoltDBRepository) Reader() *BoltDBTransaction因?yàn)檫@沒有實(shí)現(xiàn)ImageRepository接口,所以我需要一個(gè)簡(jiǎn)單的包裝器type ImageRepository struct { *BoltDBRepository }func (ir *ImageRepository) Writer() usecase.ImageReadWriterfunc (ir *ImageRepository) Reader() usecase.ImageReader作為價(jià)值的交易type ImageReader interface {    func WriteImage(tx Transaction, i Image) error}type Transaction interface {     func Commit() error}type Repository interface {    func BeginTransaction() (Transaction, error)}存儲(chǔ)庫(kù)實(shí)現(xiàn)看起來像這樣type BoltDBRepository struct {}type BoltDBTransaction struct { *bolt.Tx }// implement ImageWriterfunc (repo *BoltDBRepository) WriteImage(tx usecase.Transaction, img usecase.Image) error {  boltTx := tx.(*BoltDBTransaction)  ...}問題:雖然這可行,但我必須在每個(gè)存儲(chǔ)庫(kù)方法的開頭鍵入斷言,這看起來有點(diǎn)乏味。所以這些是我可以想出的方法。哪個(gè)最合適,或者有更好的解決方案?
查看完整描述

3 回答

?
白板的微信

TA貢獻(xiàn)1883條經(jīng)驗(yàn) 獲得超3個(gè)贊

存儲(chǔ)庫(kù)是保存數(shù)據(jù)的地方的表示,架構(gòu)元素也是如此。


事務(wù)是解決非功能需求(原子操作)的技術(shù)細(xì)節(jié),因此它必須像架構(gòu)元素中的內(nèi)部引用或私有功能一樣使用。


在這種情況下,如果您的存儲(chǔ)庫(kù)是這樣寫的:


type UserRepository interface {

    func Keep(UserData) error

    func Find(UUID) UserData

}


type ImageRepository interface {

    func Keep(ImageData) error

    func Find(UUID) ImageData

}

事務(wù)性方法是一個(gè)實(shí)現(xiàn)細(xì)節(jié),因此您可以創(chuàng)建一個(gè)像內(nèi)部引用一樣使用的 UserRepository 和 ImageRepository 的“實(shí)現(xiàn)”。


type UserRepositoryImpl struct {

    Tx Transaction

}


func (r UserRepository) func Keep(UserData) error { return r.Tx.On(...)} 

func (r UserRepository) func Find(UUID) UserData { return r.Tx.WithResult(...)}

通過這種方式,您也可以將用戶和圖像保留在單個(gè)事務(wù)中。


例如,如果客戶端引用了 userRepository 和 imageRepository 并且它負(fù)責(zé) userData 和 imageData 并且它還希望將這兩個(gè)數(shù)據(jù)保存在單個(gè)事務(wù)中,那么:


//open transaction and set in participants

tx := openTransaction()

ur := NewUserRepository(tx)

ir := NewImageRepository(tx)

//keep user and image datas

err0 := ur.Keep(userData)

err1 := ir.Keep(imageData)

//decision

if err0 != nil || err1 != nil {

  tx.Rollback()

  return

}

tx.Commit()

這是干凈、客觀的,并且在洋蔥架構(gòu)、DDD 和 3 層架構(gòu)(Martin Fowler)中運(yùn)行良好!

在洋蔥架構(gòu)中:

  • 實(shí)體:用戶和圖像(沒有業(yè)務(wù)規(guī)則)

  • Usecase : 存儲(chǔ)庫(kù)接口(應(yīng)用規(guī)則:保留用戶和圖像)

  • 控制器: A/N

  • DB/Api:客戶端、tx、存儲(chǔ)庫(kù)實(shí)現(xiàn)


查看完整回答
反對(duì) 回復(fù) 2023-03-21
?
哆啦的時(shí)光機(jī)

TA貢獻(xiàn)1779條經(jīng)驗(yàn) 獲得超6個(gè)贊

保持存儲(chǔ)庫(kù)原樣,不要嘗試在那里解決事務(wù)性 API 的想法。您需要一個(gè)單獨(dú)的存儲(chǔ)庫(kù)注冊(cè)表來控制您的存儲(chǔ)庫(kù)將如何初始化以及它們的行為方式;原子操作等這是一個(gè)很好的例子:


文件:內(nèi)部/存儲(chǔ)庫(kù)/registry.go


package repository


import (

    "context"


    "github.com/kataras/app/image"

)


type TransactionFunc = func(Registry) error


type Registry interface {

    NewImageRepository() image.Repository

    // more repo initialization funcs...


    InTransaction(context.Context, func(Registry) error) error

}

文件:內(nèi)部/存儲(chǔ)庫(kù)/注冊(cè)表/postgres.go


package registry


import (

    "context"

    "fmt"


    "github.com/kataras/app/image"

    "github.com/kataras/app/internal/repository"


    "github.com/kataras/pg" // your or 3rd-party database driver package.

)


type PostgresRepositoryRegistry struct {

    db *pg.DB

}


var _ repository.Registry = (*PostgresRepositoryRegistry)(nil)


func NewPostgresRepositoryRegistry(db *pg.DB) *PostgresRepositoryRegistry {

    return &PostgresRepositoryRegistry{

        db: db,

    }

}


func (r *PostgresRepositoryRegistry) NewImageRepository() image.Repository {

    return image.NewPostgresRepository(r.db)

}



// The important stuff!

func (r *PostgresRepositoryRegistry) InTransaction(ctx context.Context, fn repository.TransactionFunc) (err error) {

    if r.db.IsTransaction() {

        return fn(r)

    }


    var tx *pg.DB

    tx, err = r.db.BeginDatabase(ctx)

    if err != nil {

        return

    }


    defer func() {

        if p := recover(); p != nil {

            _ = tx.RollbackDatabase(ctx)

            panic(p)

        } else if err != nil {

            rollbackErr := tx.RollbackDatabase(ctx)

            if rollbackErr != nil {

                err = fmt.Errorf("%w: %s", err, rollbackErr.Error())

            }

        } else {

            err = tx.CommitDatabase(ctx)

        }

    }()


    newRegistry := NewPostgresRepositoryRegistry(tx)

    err = fn(newRegistry)


    return

}

現(xiàn)在,在您的域服務(wù)級(jí)別,您只需注入一個(gè)repository.Registry,例如PostgresRepositoryRegistry.


文件:內(nèi)部/服務(wù)/image_service.go


package service


import (

    "context"


    "github.com/kataras/app/internal/repository"

)


type ImageService struct {

    registry repository.Registry

}


func NewImageService (registry repository.Registry) *ImageService {

    return &ImageService {

        registry: registry ,

    }

}


func (s *ImageService) DoSomeWork(ctx context.Context, ...) error {

    images := s.registry.NewImageRepository()

    images.DoSomeWork(ctx, ...)

}


// Important stuff!

func (s *ImageService) DoSomeWorkInTx(ctx context.Context, inputs [T]) error {

    return s.registry.InTransaction(ctx, func(r repository.Registry) error) {

        images := r.NewImageRepository()

        for _, in := range inputs {

            if err := images.DoSomeWork(); err!=nil {

                  return err // rollback.

            }

        }


        return nil

    }


}

在您的 API 路由中使用 ImageService。


db, err := pg.Open(...)

// handleError(err)

repoRegistry := registry.NewPostgresRepositoryRegistry(db)

imageService := service.NewImageService(repoRegistry)


// controller := &MyImageController{Service: imageService}

您可以使用Iris進(jìn)行依賴注入。


查看完整回答
反對(duì) 回復(fù) 2023-03-21
?
幕布斯6054654

TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超7個(gè)贊

如果你回購(gòu)必須保留一些狀態(tài)字段


type UserRepositoryImpl struct {

    db Transaction

    someState bool

}


func (repo *UserRepositoryImpl) WithTx(tx Transaction) *UserRepositoryImpl {

    newRepo := *repo

    repo.db = tx

    return &newRepo

}


func main() {

    repo := &UserRepositoryImpl{ 

        db: connectionInit(),

        state: true,

    }


    repo.DoSomething()


    tx := openTransaction()

    txrepo := repo.WithTx(tx)


    txrepo.DoSomething()

    txrepo.DoSomethingElse()

}



查看完整回答
反對(duì) 回復(fù) 2023-03-21
  • 3 回答
  • 0 關(guān)注
  • 154 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)