Files

56 lines
1.8 KiB
Go

// Run with go run ./examples/transactions. Uses a deterministic demonstration
// driver, no external database and no actual uploaded files.
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"git.yuntuo.hk/k2safe/go-omni/database"
)
func main() {
failure := errors.New("demonstration failure")
for _, name := range []string{"success", "beginFailure", "workFailure", "rollbackFailure", "commitRejected", "commitAcknowledgementLost"} {
driver := &demoConnector{}
var workErr error
switch name {
case "beginFailure":
driver.beginErr = failure
case "workFailure":
workErr = failure
case "rollbackFailure":
workErr, driver.rollbackErr = failure, failure
case "commitRejected":
driver.commitErr = failure
case "commitAcknowledgementLost":
driver.commitErr, driver.persistBeforeError = failure, true
}
pool := &database.DB{DB: sql.OpenDB(driver)}
err := pool.InTx(context.Background(), nil, func(tx *sql.Tx) error {
if _, err := tx.ExecContext(context.Background(), "INSERT demonstration record"); err != nil {
return err
}
return workErr
})
_ = pool.Close()
if err == nil {
fmt.Printf("%s: committed, stored=%t\n", name, driver.stored.Load())
continue
}
var txErr *database.TxError
if !errors.As(err, &txErr) || !errors.Is(err, failure) {
panic("transaction phase or original cause lost")
}
// A project decides whether cleanup is appropriate for its own operation.
// Unknown outcomes must not be treated as evidence that no record exists.
cleanup := txErr.Outcome == database.TxOutcomeNotStarted || txErr.Outcome == database.TxOutcomeRolledBack
if cleanup && driver.stored.Load() {
panic("unsafe cleanup decision")
}
fmt.Printf("%s: stage=%s outcome=%s stored=%t cleanup=%t\n", name, txErr.Stage, txErr.Outcome, driver.stored.Load(), cleanup)
}
}