CUBRID provides six isolation levels — more than the SQL standard's four. This document explains each level, how to configure them, and how they compare to other databases.
- Overview
- Isolation Level Details
- Configuration
- CUBRID's Dual-Granularity Model
- Accepted Level Names
- Comparison with SQL Standard
- How the Dialect Manages Isolation
- Best Practices
| Level | Numeric | Name (Short) | Name (Full) |
|---|---|---|---|
| 6 | 6 | SERIALIZABLE |
Serializable |
| 5 | 5 | REPEATABLE READ |
Repeatable Read Schema, Repeatable Read Instances |
| 4 | 4 | READ COMMITTED (default) |
Repeatable Read Schema, Read Committed Instances |
| 3 | 3 | — | Repeatable Read Schema, Read Uncommitted Instances |
| 2 | 2 | — | Read Committed Schema, Read Committed Instances |
| 1 | 1 | — | Read Committed Schema, Read Uncommitted Instances |
The CUBRID server default is level 4 (READ COMMITTED).
The strictest isolation level. Transactions are fully serialized: no dirty reads, no non-repeatable reads, no phantom reads.
Use when: Absolute consistency is required (e.g., financial transactions, audit logs).
Trade-off: Highest lock contention, lowest concurrency.
Both schema (class-level) and data (instance-level) reads are repeatable within a transaction. No phantom reads on indexed columns.
Use when: You need consistent reads within a transaction but can tolerate slightly lower throughput than serializable.
Schema reads are repeatable; data reads see only committed values but may see different results on re-read (non-repeatable reads possible).
Use when: General-purpose OLTP workloads. The best balance of consistency and performance for most applications.
Schema reads are repeatable, but data reads may see uncommitted changes from other transactions (dirty reads possible).
Use when: Read-heavy analytics where absolute accuracy is not critical and you want to avoid data-level read locks.
Both schema and data reads see only committed values, but neither is repeatable. Schema changes from committed transactions are visible immediately.
Use when: Applications that don't modify schema during normal operation and can tolerate non-repeatable reads.
Schema reads see only committed values. Data reads may see uncommitted changes (dirty reads).
Use when: Maximum read performance in controlled environments where dirty reads are acceptable. Not recommended for production applications.
Set the default isolation level when creating the engine:
from sqlalchemy import create_engine
# Use short name
engine = create_engine(
"cubrid://dba@localhost:33000/testdb",
isolation_level="REPEATABLE READ",
)
# Use full CUBRID name
engine = create_engine(
"cubrid://dba@localhost:33000/testdb",
isolation_level="REPEATABLE READ SCHEMA, REPEATABLE READ INSTANCES",
)Set isolation level on a specific connection:
from sqlalchemy import text
with engine.connect().execution_options(
isolation_level="SERIALIZABLE"
) as conn:
result = conn.execute(text("SELECT * FROM accounts WHERE id = :id"), {"id": 1})
# This connection uses SERIALIZABLE isolationwith engine.begin() as conn:
# Switch isolation for this block
conn = conn.execution_options(isolation_level="SERIALIZABLE")
conn.execute(text("UPDATE accounts SET balance = balance - 100 WHERE id = 1"))
conn.execute(text("UPDATE accounts SET balance = balance + 100 WHERE id = 2"))
# Commits at end of blockUnlike most databases, CUBRID separates isolation into two dimensions:
- Class-level (schema operations): Controls visibility of DDL changes (table creation, column alterations)
- Instance-level (data operations): Controls visibility of DML changes (inserts, updates, deletes)
This is why CUBRID has 6 levels instead of the standard 4. The combinations are:
| Class (Schema) | Instance (Data) | Level |
|---|---|---|
| Serializable | Serializable | 6 |
| Repeatable Read | Repeatable Read | 5 |
| Repeatable Read | Read Committed | 4 |
| Repeatable Read | Read Uncommitted | 3 |
| Read Committed | Read Committed | 2 |
| Read Committed | Read Uncommitted | 1 |
In practice, most applications use levels 4 (default), 5, or 6.
The dialect accepts multiple name forms for convenience:
| Short Name | Maps To Level |
|---|---|
SERIALIZABLE |
6 |
REPEATABLE READ |
5 |
REPEATABLE READ SCHEMA, REPEATABLE READ INSTANCES |
5 |
READ COMMITTED |
4 |
REPEATABLE READ SCHEMA, READ COMMITTED INSTANCES |
4 |
CURSOR STABILITY |
4 |
REPEATABLE READ SCHEMA, READ UNCOMMITTED INSTANCES |
3 |
READ COMMITTED SCHEMA, READ COMMITTED INSTANCES |
2 |
READ COMMITTED SCHEMA, READ UNCOMMITTED INSTANCES |
1 |
Names are case-insensitive.
| SQL Standard Level | CUBRID Equivalent | Level |
|---|---|---|
READ UNCOMMITTED |
Level 1 (closest) | 1 |
READ COMMITTED |
Level 4 (default) | 4 |
REPEATABLE READ |
Level 5 | 5 |
SERIALIZABLE |
Level 6 | 6 |
Levels 2 and 3 are CUBRID-specific and have no direct SQL standard equivalent.
The dialect uses the SET TRANSACTION ISOLATION LEVEL SQL command with CUBRID's numeric level:
SET TRANSACTION ISOLATION LEVEL 5
COMMITThe COMMIT after setting isolation level is required by CUBRID to apply the change.
The dialect reads the current isolation level using CUBRID's proprietary syntax:
GET TRANSACTION ISOLATION LEVEL TO X
SELECT XThe returned numeric value is mapped back to a descriptive string.
When a connection is returned to the pool, the dialect resets isolation to level 4 (READ COMMITTED) to ensure a clean state for the next checkout.
-
Use the default (level 4) unless you have a specific reason to change it. Most web applications work correctly with
READ COMMITTED. -
Use
SERIALIZABLEsparingly. It provides the strongest guarantees but can cause significant lock contention under load. -
Avoid levels 1 and 3 in production. Dirty reads (read uncommitted instances) can lead to inconsistent application behavior.
-
Set isolation at the engine level for application-wide defaults, and override per-connection only when needed.
-
Be aware of DDL auto-commit. CUBRID auto-commits DDL statements regardless of isolation level. This means
CREATE TABLE,ALTER TABLE, etc. are immediately visible to all transactions.
flowchart LR
l1[Level 1\nRC Schema + RU Instances] --> l2[Level 2\nRC Schema + RC Instances]
l2 --> l3[Level 3\nRR Schema + RU Instances]
l3 --> l4[Level 4\nRR Schema + RC Instances\nDefault]
l4 --> l5[Level 5\nRR Schema + RR Instances]
l5 --> l6[Level 6\nSerializable]
dirty[Dirty read risk] -. highest .-> l1
dirty -. reduced .-> l3
dirty -. blocked .-> l2
dirty -. blocked .-> l4
dirty -. blocked .-> l5
dirty -. blocked .-> l6
!!! warning "Isolation level changes require COMMIT"
CUBRID applies SET TRANSACTION ISOLATION LEVEL with a commit boundary.
Plan transaction scopes accordingly when switching levels at runtime.
!!! tip "Default level 4 is a balanced baseline"
Start with READ COMMITTED (level 4), then move to level 5 or 6 only for correctness-critical paths.
See also: Connection Setup · Feature Support