blob: 15d41b37df9abfd2806b04c6d2ba4c30786e9547 [file] [log] [blame]
Title:
Notice: Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
#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 <code>org.osgi.service.transaction.control.TransactionControl</code> implementation
(found in the service registry). You may want to start with [local transactions][1].
* A <code>org.osgi.service.transaction.control.ResourceProvider</code> for each of the
resources that you want to use. You may want to start with [local JDBC][2].
##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 <code>Callable</code>. 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
<code>required</code> and <code>requiresNew</code> methods can be used to ensure that a
_Transactional_ scope has been started. The <code>supports</code> and <code>notSupported</code>
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
[more advanced scope control techniques][3] or [exception management][4] once you've mastered the basics.
There are also some things to consider if you're [migrating from Spring or Java EE][5].
##Accessing Resources
A <code>ResourceProvider</code> 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
<code>JDBCConnectionProvider</code> and <code>JPAEntityManagerProvider</code> interfaces. If
needed you can [make your own ResourceProvider][6].
To create your scoped resource you make one call to <code>getResource</code> passing in the
<code>TransactionControl</code> 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;
});
}
}
[1]: localTransactions.html
[2]: localJDBC.html
[3]: advancedScopes.html
[4]: exceptionManagement.html
[5]: spring-tx.html
[6]: advancedResourceProviders.html