Transactions are created with CubDB.transaction/2, and are used to perform arbitrary write operations atomically, using functions in CubDB.Tx.
Transactions block writers, but do not block concurrent readers.
Example:
Suppose the keys :a and :b map to balances, and we want to transfer 5 from :a to :b, if :a has enough balance:
CubDB.transaction(db, fn tx ->
a = CubDB.Tx.get(tx, :a)
b = CubDB.Tx.get(tx, :b)
if a >= 5 do
tx = CubDB.Tx.put(tx, :a, a - 5)
tx = CubDB.Tx.put(tx, :b, b + 5)
{:commit, tx, :ok}
else
{:cancel, :insufficient_balance}
end
end)
The read functions in CubDB.Tx read the in-transaction state, as opposed to the live database state, so they see writes performed inside the transaction even before they are committed:
# Assuming we start from an empty database
CubDB.transaction(db, fn tx ->
tx = CubDB.Tx.put(tx, :a, 123)
# CubDB.Tx.get sees the in-transaction value
CubDB.Tx.get(tx, :a)
# => 123
# CubDB.get instead does not see the uncommitted write
CubDB.get(db, :a)
# => nil
{:commit, tx, nil}
end)
# After the transaction is committed, CubDB.get sees the write
CubDB.get(db, :a)
# => 123
Transactions are created with
CubDB.transaction/2
, and are used to perform arbitrary write operations atomically, using functions inCubDB.Tx
.Transactions block writers, but do not block concurrent readers.
Example:
Suppose the keys
:a
and:b
map to balances, and we want to transfer 5 from:a
to:b
, if:a
has enough balance:The read functions in
CubDB.Tx
read the in-transaction state, as opposed to the live database state, so they see writes performed inside the transaction even before they are committed: