| name | transactions-php | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| summary | ACID multi-document transactions with the Couchbase PHP SDK — $cluster->transactions()->run(), TransactionAttemptContext, ctx->get/insert/replace/remove, SQL++ in transactions, error handling, durability | ||||||||||||||||||||||||||
| description | ACID multi-document transactions with the Couchbase PHP SDK — $cluster->transactions()->run(), TransactionAttemptContext, ctx->get/insert/replace/remove, SQL++ in transactions, error handling, durability | ||||||||||||||||||||||||||
| compatibility | PHP SDK 4.x. Requires Couchbase Server 6.6.1+ or Capella. | ||||||||||||||||||||||||||
| metadata |
|
Transactions are ACID, multi-document, and automatically retried on transient failures. The lambda may run more than once — keep it idempotent and free of side effects.
Version requirement: Distributed transactions require Couchbase Server 7.0+. The 6.6 developer preview is not recommended for production.
use Couchbase\TransactionAttemptContext;
use Couchbase\TransactionOptions;
use Couchbase\Exception\TransactionFailedException;
try {
$cluster->transactions()->run(function (TransactionAttemptContext $ctx) use ($collection) {
// Insert
$ctx->insert($collection, "doc-a", ["status" => "new"]);
// Get
$docA = $ctx->get($collection, "doc-a");
// Replace
$content = $docA->content();
$content["status"] = "processed";
$ctx->replace($docA, $content);
// Remove
$docB = $ctx->get($collection, "doc-b");
$ctx->remove($docB);
});
echo "Transaction committed\n";
} catch (TransactionFailedException $e) {
echo "Transaction failed: " . $e->getMessage() . "\n";
}try {
$cluster->transactions()->run(function (TransactionAttemptContext $ctx) use ($collection) {
$from = $ctx->get($collection, "account::alice");
$to = $ctx->get($collection, "account::bob");
$fromDoc = $from->content();
$toDoc = $to->content();
$amount = 100;
if ($fromDoc["balance"] < $amount) {
throw new \Exception("Insufficient funds");
}
$fromDoc["balance"] -= $amount;
$toDoc["balance"] += $amount;
$ctx->replace($from, $fromDoc);
$ctx->replace($to, $toDoc);
});
} catch (TransactionFailedException $e) {
echo "Transfer failed: " . $e->getMessage() . "\n";
}use Couchbase\TransactionQueryOptions;
$cluster->transactions()->run(function (TransactionAttemptContext $ctx) {
$ctx->query(
"UPDATE `travel-sample`.`inventory`.`airline` SET status = 'active' WHERE country = \$1",
TransactionQueryOptions::build()->positionalParameters(["US"])
);
});use Couchbase\DurabilityLevel;
$opts = TransactionOptions::build()
->durabilityLevel(DurabilityLevel::PERSIST_TO_MAJORITY);
$cluster->transactions()->run(function (TransactionAttemptContext $ctx) use ($collection) {
$ctx->insert($collection, "order::1", ["status" => "pending"]);
}, $opts);use Couchbase\Exception\TransactionFailedException;
use Couchbase\Exception\TransactionCommitAmbiguousException;
try {
$cluster->transactions()->run(function (TransactionAttemptContext $ctx) use ($collection) {
// transaction logic
});
} catch (TransactionCommitAmbiguousException $e) {
// Transaction may or may not have committed — check and handle
echo "Ambiguous commit: " . $e->getMessage() . "\n";
} catch (TransactionFailedException $e) {
// Transaction did not commit
echo "Failed: " . $e->getMessage() . "\n";
}- Keep transactions under 1 second — long transactions increase conflict probability
- SDK retries automatically on transient conflicts — don't add your own retry loop
- No cross-bucket transactions
OnUpdateEventing fires after commit, not within the transaction