Working with Transactions |
![]() |
A transaction is a read-write view on the current state of a repository
branch. It shares the view concepts explained in Working with Views, but additionally records local
model changes until they are committed or rolled back.
A root transaction commit is the operation that persists the effective changes in the repository. Savepoints and nested scopes are client-side composition mechanisms; completing either one does not create a repository commit. Server applications that validate or observe these commits use the supported handlers described in Repository Handlers and Commit Processing.
Table of Contents
Transactions are opened from a session. The session supplies the repository connection and
the transaction owns its view and resource set until it is closed. The common overload of
openTransaction() and the more specific overloads inherited from
CDOTransactionContainer allow an application to select a branch point,
resource set, or durable-locking identity.
A transaction remains usable after a successful commit, so an application can perform another unit of work or close it. Closing the transaction releases its client-side resources; it does not replace commit or rollback.
A transaction is dirty when it contains uncommitted changes. The public transaction API exposes separate maps
for new, detached, and modified objects through CDOTransaction.getNewObjects(),
CDOTransaction.getDetachedObjects(), and CDOTransaction.getDirtyObjects().
CDOTransaction.getRevisionDeltas() exposes the revision-level changes.
These collections describe the transaction's current local state. They are not a second repository history and are cleared or reduced as changes are committed or rolled back.
CDOTransaction.commit() sends the transaction's effective changes to the repository and returns a
commit-info object. The transaction stays open after a successful commit. Commit comments
and arbitrary commit properties can be set with CDOTransaction.setCommitComment(String) and
CDOTransaction.setCommitProperty(String, String); committed metadata can be observed through the
commit-info manager.
A commit can fail with CommitException, including a CommitConflictException or an
OptimisticLockingException. Applications must not assume that acquiring explicit locks eliminates every
possible commit failure.
CDOTransaction.hasConflict() and CDOTransaction.getConflicts() expose objects whose local
modifications conflict with remote changes. A configured conflict resolver can resolve conflicts during invalidation; otherwise an application commonly rolls back,
reapplies its business operation against the current view, and commits again.
The retry overloads of CDOTransaction.commit(Runnable, int, IProgressMonitor) and its
Callable counterpart run the operation before each attempt. The integer is the total attempt
count, so 3 permits one initial attempt and two retries. When a ConcurrentAccessException
occurs, CDO rolls back the failed attempt before trying again; other commit failures are not retried by this
overload. The operation supplied for retry must therefore be repeatable and must reapply the intended changes.
CDOTransaction.rollback() removes all uncommitted changes from the root transaction and leaves the
transaction open for further work. It is different from rolling back a savepoint, which
retains the earlier part of the transaction, and from rolling back a scope, which
affects only that scope and its descendants.
A transaction can restrict one commit to a set of committable objects with
CDOTransaction.setCommittables(Set). CDO filters the transaction's new, dirty, and detached objects against
this set; it does not automatically compute a dependency closure. If a selected object refers to a new object that
is not selected, the intended commit may be incomplete or violate model constraints. Include the full set needed
for a valid repository change. Non-selected changes remain local and the transaction stays dirty. Use partial
commits only when those staged boundaries make sense to the domain; independent business units are usually easier
to reason about as separate transactions.
CDOTransaction.setSavepoint() creates an in-memory client-side boundary in the transaction's change
history. CDOUserSavepoint.rollback() restores the transaction to that boundary by undoing changes made
after it, while keeping the root transaction active. Savepoints do not flush changes to disk or to the repository.
CDOSavepoint is the richer transaction-specific view of the same boundary. It exposes the objects and
revision deltas belonging to a savepoint, including CDOSavepoint.getDirtyObjects() and
CDOSavepoint.getAllChangeSetData(). Use those inspection APIs only when the application needs to reason
about the change segment itself.
CDOTransaction.openScope() creates a stack-disciplined scope inside the root transaction. A scope shares
the transaction's view, resource set, object identities, cache, dirty state, locks, and session. Its changes are
immediately visible in the containing transaction.
CDOTransactionScope.commit() accepts the scope into its parent but never persists anything to the
repository. CDOTransactionScope.rollback() restores the state at the scope boundary, and
CDOTransactionScope.close() rolls back an active scope. Only a later commit on the root
CDOTransaction creates the repository commit. Scopes may be nested and must be completed from the
innermost scope outward.
CDOTransactionScope.asTransaction() supplies a stable nested transaction facade for APIs that accept a
transaction. Commit operations on that facade are unsupported; the scope itself is completed with
CDOTransactionScope.commit().
CDOTransaction.merge(CDOBranch, CDOMerger) and the related branch-point overloads apply changes from a
source branch or branch point to the local transaction. They create local changes; the caller still decides when
to commit them. The returned CDOChangeSetData describes the applied change set. Merge conflicts are part
of the transaction conflict model and must be resolved before a successful commit.
Branch selection and historical branch points belong in the Branching and Versioning chapter. This section is limited to the transaction side of applying and committing a merge.
CDOTransaction.revertTo(CDOBranchPoint) creates local changes that restore the transaction's model to a
specified historical branch point. Revert is not the same as rollback: rollback
discards uncommitted local work, whereas revert prepares a new change set that can itself be reviewed and committed.
It is also distinct from a savepoint rollback and from opening a historical read-only view.
CDOTransaction.exportChanges(OutputStream) serializes the transaction's local changes to an output
stream and CDOTransaction.importChanges(InputStream, boolean) applies serialized transaction
changes from an input stream. The boolean controls whether savepoints are reconstructed while importing. These
operations work with transaction changes; they are not repository commits, raw revision history exports, or
generic model serialization.
The file-backed transaction described below uses these APIs internally, but they can also be used directly when an application controls the transfer stream.
CDOFileTransaction is the current public API for persisting uncommitted changes in its stable backing file
(available through CDOFileTransaction.getFile()) and later pushing them to the repository. Its normal
CDOFileTransaction.commit() persists the current uncommitted changes to that file and does not commit to
the repository; CDOFileTransaction.push() performs the repository commit and removes the persisted file
after success. The inherited rollback operation is unsupported, as are the inherited callable and runnable commit
overloads. File-backed transactions are therefore appropriate for explicit export-and-push workflows rather than
ordinary rollback-based editing.
The older CDOPushTransaction API is deprecated as of 4.30 in favor of CDOFileTransaction and is
not used in this example.
General querying is covered in the Views chapter. A transaction additionally offers
CDOTransaction.createQuery(String, String, boolean) and its context overload, whose
considerDirtyState argument controls whether CDO adds the transaction's local change-set data to the
query request. This lets query implementations that support change-set data account for new, modified, and
detached objects alongside repository results. It does not execute an arbitrary query over a complete in-memory
copy, and a custom query handler must honor the supplied change-set data for the option to affect its results.
Use true when asking about the transaction's working state; the default repository-only query answers a
different question.
CDOTransaction.options() exposes the transaction-specific options in addition to the view options
described in the Views chapter. Application developers should normally consider three groups: conflict resolvers
for automatic handling of remote conflicts; optimistic-locking and commit-info timeouts for bounded commit
behavior; and automatic lock release, including its exemptions, for predictable lock ownership after commit or
rollback.
The options API is intentionally linked rather than duplicated here. Its Javadoc documents defaults and the complete option set, including undo detection, stale-reference cleaning, and attached-revision handling.