strolch-website/content/documentation/transactions.md

101 lines
3.1 KiB
Markdown
Raw Normal View History

2021-07-11 20:36:03 +02:00
---
title: 'Transactions'
weight: 90
---
## Transactions
Strolch Transactions play a central role in a Strolch agent. A transaction is
opened for a realm, and grants access to the model of the agent. Transactions
are implemented as a Java `try-with-resources` by implementing
the `AutoCloseable`
interface. This makes it trivial to understand the scope of a transaction.
Transactions handle the following:
* Opening and closing database connections
* Releasing locks to strolch elements, if `tx.lock(StrolchRootElement)` or
`tx.lock(Locator)` was called
* Performing Commands by executing them in the added order, and validating them
first.
* Exception handling
* Auditing
* Updating observers
When a transaction is opened, it is by default read-only, i.e. does not perform
any commands when it is closed. Should the TX perform commands, then it is
important to call `tx.commitOnClose()`, but only at the end of the work, so that
exception handling can properly work if something goes wrong.
`StrolchTransaction` offers a myriad of methods:
* find element by its `Locator`
* get methods for elements by type and id, or using a `StringParameter` or
`StringListParameter` references
* methods to add, update or remove elements
* assert privilege access
* get a new element by its template
* check if an element exists by type and id
* get streams for elements
* add commands for execution
Transactions are opened by accessing the realm, but there are convenience
methods depending on the use-case:
* In Services: by calling one of the `openTx()`-methods
* In Commands: Transactions are already open, use method `tx()` to get instance.
* REST API: `RestfulStrolchComponent.openTx()`
{{% notice warning %}}
Note: don't open a new TX inside a TX for the same realm!
{{% /notice %}}
Important is to always open the transaction as a `try-with-resource` block and to
define if the TX should commit, or not:
```java
try (StrolchTransaction tx = openTx(...)) {
// read lock our object
Locator ferrariLoc = Resource.locatorFor("Car", "ferrari");
tx.lock(ferrariLoc);
// find a car by locator
Resource ferrari = tx.findElement(ferrariLoc);
// get a car by ID
Resource opel = tx.getResourceBy("Car", "opel", true);
// modify ball
opel.setName("Opel Corsa");
tx.update(opel);
// get by string reference
StringParameter ownerP = ferrari.getParameter("relations", "owner", true);
Resource owner = tx.getResourceBy(ownerP, true);
// get by string list reference
StringListParameter previousOwnersP = opel.getParameter("relations", "previousOwners", true);
List<Resource> previousOwners = tx.getResourcesBy(previousOwnersP, true);
// check resource exists
if (tx.hasResource("Car", "audi")) {
Resource audi = tx.getResourceBy("Car", "audi", true);
// assert has privilege to remove a car
tx.assertHasPrivilege(Operation.REMOVE, audi);
// remove the car
tx.remove(audi);
}
// iterate all cars
tx.streamResources("Car").forEach(car -> {
logger.info("Car: " + car.getId());
});
// commit if TX was changed
if (tx.needsCommit())
tx.commitOnClose();
}
```