// 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) } }