blob: d1c68665f4bbfc213584ead119c93e2272d8daa9 [file] [log] [blame]
= Getting started with the Transaction Control Service
To make use of scoped resources and transactions using the transaction control service you need two things:
* A `org.osgi.service.transaction.control.TransactionControl` implementation (found in the service registry).
You may want to start with link:localTransactions.html[local transactions].
* A `org.osgi.service.transaction.control.ResourceProvider` for each of the resources that you want to use.
You may want to start with link:localJDBC.html[local JDBC].
== Scoping Work using TransactionControl
The Transaction Control Service defines three different scopes:
* Unscoped - There is no scope associated with the current thread
* _No Transaction Scope_ - There is a scope associated with the current thread, but no ongoing transaction
* _Transactional Scope_ - There is an ongoing transaction associated with the current thread
Scoped resources have different behaviours in each of these three scopes:
* Unscoped - The resource is generally not usable and will throw exceptions
* _No Transaction_ Scope - The same physical resource will be used throughout the scope, and will be automatically tidied up at the end of the scope (e.g.
closed or returned to a pool)
* _Transactional Scope_ - The same physical resource will be used throughout the scope, will be automatically committed or rolled back up at the end of the transaction, and then tidied up afterwards
=== Starting and Finishing scopes
A scope is defined using a piece of work wrapped in a `Callable`.
This means that it is lambda-friendly.
Integer result = txControl.required(() -> {
//Work goes in here
return 42;
});
The scope starts immediately before the work is executed, and finishes immediately afterwards.
The `required` and `requiresNew` methods can be used to ensure that a _Transactional_ scope has been started.
The `supports` and `notSupported` methods can be used to ensure that a _No Transaction_ scope has been started.
Simple scope management is perfect in most situations, but you may also wish to read about link:advancedScopes.html[more advanced scope control techniques] or link:exceptionManagement.html[exception management] once you've mastered the basics.
There are also some things to consider if you're link:spring-tx.html[migrating from Spring or Java EE].
== Accessing Resources
A `ResourceProvider` is a generic factory for scoped resources.
Typically you will use a more specific interface for type safety.
For example the Transaction Control specification defines `JDBCConnectionProvider` and `JPAEntityManagerProvider` interfaces.
If needed you can link:advancedResourceProviders.html[make your own ResourceProvider].
To create your scoped resource you make one call to `getResource` passing in the `TransactionControl` service that the resource should integrate with.
The returned object is thread-safe, and can be cached for use in any scope.
=== Declarative Services Example
The following component provides read and write access using JDBC to a list of messages created by a user.
The transactionality and lifecycle of the database resources is automatically managed.
....
@Component
public class MyDaoImpl implements MyDao {
@Reference
TransactionControl control;
Connection dbConn;
@Reference
void setResource(JDBCConnectionProvder provider) {
dbConn = provider.getResource(control);
}
@Override
public void saveMessage(String user, String message) {
txControl.required(() -> {
PreparedStatement ps = connection.prepareStatement(
"Insert into MESSAGES values ( ?, ? )");
ps.setString(1, user);
ps.setString(2, message);
return ps.executeUpdate();
});
}
@Override
public void getMessagesForUser(String user) {
return txControl.supports(() -> {
PreparedStatement ps = connection.prepareStatement(
"Select MESSAGE FROM MESSAGES WHERE USER = ?");
ps.setString(1, user);
List<String> result = new ArrayList<>();
ResultSet rs = ps.executeQuery();
while(rs.next()) {
result.add(rs.getString(1));
}
return result;
});
}
}
....