But in both ways it’s important to understand the transactional behavior inside of the Oracle SCA Container for Spring Beans. Transactional behavior could be influenced by declarative transaction management on the Spring Bean context configuration or in a programmatic way. For Spring Beans there is no property configuration available on the SCDL (like for example the bpel.config.transaction property for BPEL process transaction configuration).
Spring Beans used on Oracle SCA Composites are always taking part in running transactions as default behavior. If there is no caller transaction running, the Spring Bean Component starts a new transaction. This behavior needs no additional configuration and would be the desired behavior in most use cases.
If the Spring Bean should deviate from the default transactional behavior the Spring Beans needs some special configuration on the context configuration file. Therefore a transactional proxy has to be defined on Spring Bean context. The bean definition should state the transaction manager that should be used and the transactional attributes for the service object (referenced by the target property).
The following example is showing a transactional proxy configuration for the Calculator Service Bean. The example assumes existing audit tracking method(s) which should not take part in running transactions (PROPAGATION_REQUIRES_NEW).
The PROPAGATION_REQUIRES_NEW transactional attribute uses a completely independent transaction and will not affect outer transactions. Set the key attribute on “*” in order to set the transaction attribute for all methods.
This is a list of valid transaction attributes supported by the Spring Framework:
- PROPAGATION_MANDATORY: Supports a current transaction; throw an exception if no current transaction exists.
- PROPAGATION_NESTED: Executes within a nested transaction if a current transaction exists, behaves like PROPAGATION_REQUIRED else.
- PROPAGATION_NEVER: Does not support a current transaction; throws an exception if a current transaction exists.
- PROPAGATION_NOT_SUPPORTED: Does not support a current transaction; rather always executes non-transactionally.
- PROPAGATION_REQUIRED: Supports a current transaction; creates a new one if none exists.
- PROPAGATION_REQUIRES_NEW: Creates a new transaction, suspends the current transaction if one exists.
- PROPAGATION_SUPPORTS: Supports a current transaction; executes non-transactionally if none exists.
Another alternative way to the declarative solution is the programmatic approach. A Spring Bean can get a reference to the running transaction, whenever the Spring Bean needs to have programmatic access to the transaction in order to do commit, rollback, suspend or resume a running transaction.
The following listing shows an example on how a Spring Bean could get access of the running transaction. In this example the auditTracking operation is not part of the running global transaction.
Transaction transaction = null; TransactionManager txMg = null; try { ctx = new InitialContext(); // getting the transaction manager txMg = (TransactionManager) ctx.lookup("javax.transaction.TransactionManager"); // suspending the thread's transaction transaction = txMg.suspend(); // call audit tracking method // this operation is not part of the global transaction auditTracking(msg); } catch (NamingException e) { … } catch (Exception e) { … } finally { try { // resuming the transaction txMg.resume(transaction); } catch (…) { … } |
Note that in the example above, the auditTracking operation on the given example will not start an own transaction by default. This is a programmatic approach and the programmer has to take care of all kinds of transaction aspects. In my opinion the declarative approach is much more elegant because it lets the code free of any transactional requirements and centralize the configuration on the Spring Bean context.
In a composite to composite calling scenario take care that Local Optimization happens (take a look on the blog from Ramkumar Menon on how to check if Local Optimization is kicking in the WS Binding) because otherwise the normal composite to composite transaction propagation is not supported. The Oracle documentation mentions that even WS-AT will not help in this scenario (chapter 35.1.1.1.2: “WS-AT transactions are not supported in composite-to-composite calls, even with the oracle.webservices.local.optimization property set to false.”). I’m not sure if this statement is in general true.
Thanks to Clemens Utschig-Utschig who was pointing me on the declarative solution. Also thanks to Silviu Leahu who figured out the programmatic solution.
That’s it. For more details take a look at the Spring JDBC documentation.