If multiple users are accessing data at the same time, you might want to place your data table operations in a transaction. This ensures your Data Table operations are carried out as a group.
If multiple transactions are taking place at once, Anvil ensures each transaction’s Data Tables operations are completed together. From the Data Table’s perspective, it’s as if every transaction block is executing one after another.
If an exception is raised before the transaction is complete, all changes are discarded. If two transactions conflict - that is, they’ve written to the same row of a Data Table, or one transaction writes into a row another is reading from - one or both of them will be aborted.
The easiest way to perform operations in a transaction is to call a function decorated with
@anvil.tables.in_transaction. If an
@anvil.tables.in_transaction function aborts due to conflict, it will try again (after a short timeout) up to 5 times before throwing an exception.
# Server code only import anvil.tables @anvil.server.callable @anvil.tables.in_transaction def do_update(): jane_smith = app_tables.people.get(Name="Jane Smith") jane_smith['age'] = 21 app_tables.notes.add(Person=jane_smith, Text="She's old enough to fly an aeroplane.")
You can specify
@anvil.server.callable to make a callable server function transactional. Make sure to specify
@anvil.server.callable. Python applies function decorators from “inside” to “outside”, and you want the
in_transaction decorator applied before you make the function callable.)
You can also create transactions by creating a
with anvil.tables.Transaction(): block. This will not automatically retry conflicting transactions: If a transaction is aborted because of a conflict, a
tables.TransactionConflict exception is thrown. You can also abort a transaction manually by calling
.abort() on a transaction.
import anvil.tables with anvil.tables.Transaction() as txn: jane_smith = app_tables.people.get(Name="Jane Smith") jane_smith['age'] += 10
If you observe a
TransactionConflict, it is generally safe to retry. You could write a loop that detects a conflict and tries again, but this is such a common pattern that it is usually preferable to use
@anvil.tables.in_transaction (which retries the transaction automatically, up to 5 times, before throwing the
TransactionConflict as normal.)