trm

package module
v2.0.0-rc4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2023 License: MIT Imports: 5 Imported by: 2

README

Go transaction manager

Go Reference Test Status Coverage Status Go Report Card License

Transaction manager is an abstraction to coordinate database transaction boundaries.

Easiest way to get the perfect repository.

Supported implementations

Installation

go get github.com/avito-tech/go-transaction-manager/v2

To install some support database use go get github.com/avito-tech/go-transaction-manager/v2/drivers/{name}.

For example go get github.com/avito-tech/go-transaction-manager/v2/drivers/sqlx/v2.

Backwards Compatibility

The library is compatible with the most recent two versions of Go. Compatibility beyond that is not guaranteed.

Usage

To use multiple transactions from different databases, you need to set CtxKey in Settings by WithCtxKey.

For nested transactions with different transaction managers, you need to use ChainedMW (docs).

To skip a transaction rollback due to an error, use ErrSkip or Skippable

Explanation of the approach (English, Russian)
Examples with an ideal repository and nested transactions.

Below is an example how to start usage.

package main

import (
	"context"
	"fmt"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"

	trmsqlx "github.com/avito-tech/go-transaction-manager/v2/drivers/sqlx/v2"
	"github.com/avito-tech/go-transaction-manager/v2/manager"
)

func main() {
	db, err := sqlx.Open("sqlite3", "file:test?mode=memory")
	checkErr(err)
	defer db.Close()

	sqlStmt := `CREATE TABLE IF NOT EXISTS user (user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, username TEXT);`
	_, err = db.Exec(sqlStmt)
	checkErr(err, sqlStmt)

	r := newRepo(db, trmsqlx.DefaultCtxGetter)
	ctx := context.Background()
	trManager := manager.Must(trmsqlx.NewDefaultFactory(db))
	u := &user{Username: "username"}

	err = trManager.Do(ctx, func(ctx context.Context) error {
		checkErr(r.Save(ctx, u))

		// example of nested transactions
		return trManager.Do(ctx, func(ctx context.Context) error {
			u.Username = "new_username"
			return r.Save(ctx, u)
		})
	})
	checkErr(err)

	userFromDB, err := r.GetByID(ctx, u.ID)
	checkErr(err)

	fmt.Println(userFromDB)
}

func checkErr(err error, args ...interface{}) {
	if err != nil {
		panic(fmt.Sprint(append([]interface{}{err}, args...)...))
	}
}

type repo struct {
	db     *sqlx.DB
	getter *trmsqlx.CtxGetter
}

func newRepo(db *sqlx.DB, c *trmsqlx.CtxGetter) *repo {
	return &repo{db: db, getter: c}
}

type user struct {
	ID       int64  `db:"user_id"`
	Username string `db:"username"`
}

func (r *repo) GetByID(ctx context.Context, id int64) (*user, error) {
	query := "SELECT * FROM user WHERE user_id = ?;"
	u := user{}

	return &u, r.getter.DefaultTrOrDB(ctx, r.db).GetContext(ctx, &u, r.db.Rebind(query), id)
}

func (r *repo) Save(ctx context.Context, u *user) error {
	query := `UPDATE user SET username = :username WHERE user_id = :user_id;`
	if u.ID == 0 {
		query = `INSERT INTO user (username) VALUES (:username);`
	}

	res, err := sqlx.NamedExecContext(ctx, r.getter.DefaultTrOrDB(ctx, r.db), r.db.Rebind(query), u)
	if err != nil {
		return err
	} else if u.ID != 0 {
		return nil
	} else if u.ID, err = res.LastInsertId(); err != nil {
		return err
	}

	return err
}

Benchmark

Comparing examples with and without trm.

Contribution

  1. To local development sync dependencies by make go.work.sync.
  2. After finalizing of changes bump up version in all drivers.
  • To install all dependencies use make go.mod.tidy or make go.mod.vendor.
  • To run all tests use make go.test or make go.test.with_real_db for integration tests.

Documentation

Overview

Package trm contains of interfaces to programmatic transaction management.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrTransaction is an error while working with a transaction.
	ErrTransaction = errors.New("transaction")
	// ErrAlreadyClosed occurs if the transaction was closed outside the Manager.
	ErrAlreadyClosed = errTransaction("already closed")

	// ErrBegin occurs when a transaction started with an error.
	ErrBegin = errTransaction("begin")
	// ErrCommit occurs when commit finished with an error.
	ErrCommit = errTransaction("commit")
	// ErrRollback occurs when rollback finished with an error.
	ErrRollback = errTransaction("rollback")

	// ErrNestedBegin occurs when nested transaction started with an error.
	ErrNestedBegin = errNested(ErrBegin, "nested")
	// ErrNestedCommit occurs when nested transaction finished with an error.
	ErrNestedCommit = errNested(ErrCommit, "nested")
	// ErrNestedRollback occurs when rollback nested transaction finished with an error.
	ErrNestedRollback = errNested(ErrRollback, "nested")
)
View Source
var (
	// ErrPropagation occurs because of Propagation setting.
	ErrPropagation = errTransaction("propagation")
	// ErrPropagationMandatory occurs when the transaction doesn't exist.
	ErrPropagationMandatory = errNested(ErrPropagation, "mandatory")
	// ErrPropagationNever occurs when the transaction already exists.
	ErrPropagationNever = errNested(ErrPropagation, "never")
)
View Source
var ErrSkip = errors.New("skippable")

ErrSkip marks error to skip rollback for transaction because of inside error.

Functions

func IsSkippable

func IsSkippable(err error) bool

IsSkippable checks that the error is ErrSkip.

func Skippable

func Skippable(err error) error

Skippable marks error as ErrSkip.

func UnSkippable

func UnSkippable(err error) error

UnSkippable removes ErrSkip from error.

Types

type CtxGetter

type CtxGetter func(ctx context.Context) Transaction

CtxGetter gets Transaction from context.Context.

type CtxKey

type CtxKey interface{}

CtxKey is a type to identify trm.Transaction in a context.Context.

type Manager

type Manager interface {
	// Do processes a transaction inside a closure.
	Do(context.Context, func(ctx context.Context) error) error
	// DoWithSettings processes a transaction inside a closure with custom trm.Settings.
	DoWithSettings(context.Context, Settings, func(ctx context.Context) error) error
}

Manager manages a transaction from Begin to Commit or Rollback.

type NestedTrFactory

type NestedTrFactory interface {
	Begin(ctx context.Context, s Settings) (context.Context, Transaction, error)
}

NestedTrFactory creates nested Transaction.

type Propagation

type Propagation int8

Propagation is a type for transaction propagation rules.

const (
	// PropagationRequired supports a current transaction, create a new one if none exists. This is default setting.
	PropagationRequired Propagation = iota
	// PropagationNested executes within a nested transaction
	// if a current transaction exists, create a new one if none exists.
	PropagationNested
	// PropagationsMandatory supports a current transaction, throws an exception if none exists.
	PropagationsMandatory
	// PropagationNever executes non-transactionally, throws an exception if a transaction exists.
	PropagationNever
	// PropagationNotSupported executes non-transactionally, suspends the current transaction if one exists.
	PropagationNotSupported
	// PropagationRequiresNew creates a new transaction, suspends the current transaction if one exists.
	PropagationRequiresNew
	// PropagationSupports supports a current transaction, execute non-transactionally if none exists.
	PropagationSupports
)

type Settings

type Settings interface {
	// EnrichBy fills nil properties from external Settings.
	EnrichBy(external Settings) Settings

	// CtxKey returns trm.CtxKey for the trm.Transaction.
	CtxKey() CtxKey
	CtxKeyOrNil() *CtxKey
	SetCtxKey(*CtxKey) Settings

	// Propagation returns trm.Propagation.
	Propagation() Propagation
	PropagationOrNil() *Propagation
	SetPropagation(*Propagation) Settings

	// Cancelable defines that parent trm.Transaction can cancel child trm.Transaction or goroutines.
	Cancelable() bool
	CancelableOrNil() *bool
	SetCancelable(*bool) Settings

	// TimeoutOrNil returns time.Duration of the trm.Transaction.
	TimeoutOrNil() *time.Duration
	SetTimeout(*time.Duration) Settings
}

Settings is the configuration of the Manager. Preferable to implement as an immutable struct.

settings.Settings is a default implementation of Settings.

type TrFactory

type TrFactory func(ctx context.Context, s Settings) (context.Context, Transaction, error)

TrFactory is used in Manager to creates Transaction.

type Transaction

type Transaction interface {
	// Transaction returns the real transaction sql.Tx, sqlx.Tx or another.
	Transaction() interface{}
	// Commit the trm.Transaction.
	// Commit should be used only inside of Manager.
	Commit(context.Context) error
	// Rollback the trm.Transaction.
	// Rollback should be used only inside of Manager.
	Rollback(context.Context) error
	// IsActive returns true if the transaction started but not committed or rolled back.
	IsActive() bool
}

Transaction wraps different transaction implementations.

type СtxManager

type СtxManager interface {
	// Default gets Transaction from context.Context by default CtxKey.
	Default(ctx context.Context) Transaction
	// SetDefault sets.Transaction in context.Context by default CtxKey.
	SetDefault(ctx context.Context, t Transaction) context.Context

	// ByKey gets Transaction from context.Context by CtxKey.
	ByKey(ctx context.Context, key CtxKey) Transaction
	// SetByKey sets Transaction in context.Context by.CtxKey.
	SetByKey(ctx context.Context, key CtxKey, t Transaction) context.Context
}

СtxManager sets and gets a Transaction in/from context.Context.

Directories

Path Synopsis
Package context implement a setter and getter to put and get trm.Transaction from context.Context.
Package context implement a setter and getter to put and get trm.Transaction from context.Context.
internal
Package manager implements a trm.Manager interface.
Package manager implements a trm.Manager interface.
mock
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.
Package mock implements dependencies for testing.
Package mock implements dependencies for testing.
Package settings implements trm.Settings.
Package settings implements trm.Settings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL