Explicit transaction boundaries or compensating actions after Ballerina schema change
0 reputation · 08 Jun 2026, 16:54 UTC
0 reputation · 08 Jun 2026, 16:54 UTC
In Ballerina, a transaction that includes a DDL statement may not reliably revert the database to its pre-change state upon rollback, because JDBC driver implementations vary in their treatment of transactional DDL. Some drivers silently absorb the change, others raise errors, and some leave partial artifacts, creating ambiguity across Ballerina versions and database back ends. The transaction API offers begin, commit, and rollback primitives, but applying DDL within a transaction does not guarantee atomic reversal in all supported environments.
Alternatively, the compensating transaction pattern treats schema changes as reversible operations, yet the developer must manually define, sequence, and verify each inverse step, and no built-in mechanism detects omitted or duplicated compensating actions.
What criteria should determine whether to rely on explicit transaction boundaries or compensating actions for schema-change safety in Ballerina? Does Ballerina 1.5+ provide version-specific guidance on DDL rollback behavior? How does the transactional outbox pattern interact with this decision when eventual consistency is acceptable?
35275 reputation · 08 Jun 2026, 17:49 UTC
Use explicit transaction boundaries only when your target database natively supports transactional DDL (e.g., PostgreSQL, SQL Server, Oracle). Use compensating actions when the database performs implicit commits on DDL (e.g., MySQL, MariaDB) or when the schema change must coordinate across multiple services where a single database transaction cannot span all participants.
Ballerina's sql:Client and transaction API (sql:beginTransaction, commit, rollback) delegate DDL execution to the underlying JDBC driver. The driver, in turn, obeys the database engine's rules:
CREATE TABLE, ALTER TABLE, DROP TABLE run inside the transaction and roll back cleanly.rollback() cannot undo the DDL.CREATE DATABASE) autocommit.Ballerina 1.5+ does not add a language-level abstraction that normalizes this behavior. The release notes and ballerina/sql module documentation continue to state that transaction semantics follow the JDBC driver and database. No version-specific guidance overrides the engine-dependent reality.
transaction {
_ = check db->execute(`CREATE TABLE test_rollback (id INT)`);
// force failure
error? err = db->execute(`INVALID SQL`);
check err;
} else {
// rollback executed automatically
}
test_rollback exists. If it does, your database/driver does not support transactional DDL for that statement.If verification shows DDL is not transactional, define a compensating script before applying the forward migration:
CREATE with a DROP IF EXISTS.ALTER TABLE … ADD COLUMN with ALTER TABLE … DROP COLUMN IF EXISTS.Caution: Compensating actions are not atomic. A failure halfway through leaves the schema in an intermediate state that may require manual intervention.
The transactional outbox pattern writes domain events to an outbox table inside the same local transaction that commits the schema change (or the compensating action's final step). This guarantees:
When eventual consistency is acceptable, the outbox decouples the schema-change safety decision from downstream notification reliability. You still must choose transactions vs. compensations for the schema change itself; the outbox only ensures that once the schema state is final, the event is not lost.
Which database engine and major version are you targeting? If you confirm PostgreSQL ≥ 12 or SQL Server ≥ 2019, explicit transactions are safe for most DDL. If MySQL/MariaDB or an older engine, plan compensating actions.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.