You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2016/05/20 15:20:46 UTC

svn commit: r1744756 - in /aries/site/trunk/content/modules: transactioncontrol.mdtext tx-control/quickstart.mdtext tx-control/spring-tx.mdtext

Author: timothyjward
Date: Fri May 20 15:20:46 2016
New Revision: 1744756

URL: http://svn.apache.org/viewvc?rev=1744756&view=rev
Log:
Add a page describing Spring migration and problems with proxies

Added:
    aries/site/trunk/content/modules/tx-control/spring-tx.mdtext   (with props)
Modified:
    aries/site/trunk/content/modules/transactioncontrol.mdtext
    aries/site/trunk/content/modules/tx-control/quickstart.mdtext

Modified: aries/site/trunk/content/modules/transactioncontrol.mdtext
URL: http://svn.apache.org/viewvc/aries/site/trunk/content/modules/transactioncontrol.mdtext?rev=1744756&r1=1744755&r2=1744756&view=diff
==============================================================================
--- aries/site/trunk/content/modules/transactioncontrol.mdtext (original)
+++ aries/site/trunk/content/modules/transactioncontrol.mdtext Fri May 20 15:20:46 2016
@@ -16,7 +16,8 @@ ensure that the implementations are comp
 
 #Getting started
 
-If you're new to the Transaction Control service then we recommend that you read the [quickstart documentation first][2].
+If you're new to the Transaction Control service then we recommend that you read the 
+[quickstart documentation first][2].
 
 More detailed documentation is available in the [Aries Transaction Control Project][3]
 
@@ -26,31 +27,35 @@ Simply put the Transaction Control servi
 transaction lifecycle or closing connections, and there's built in support for useful features like 
 connection pooling.
 
+In addition to being simple the Transaction Control service also makes transaction management explicit. As a
+result it is easier to follow the transactions flowing throughout your code, and it protects you from the 
+[proxy problem][4] that declarative transaction strategies often suffer from.
+
 ## Modules
 
 The following modules are available for use in OSGi
 
-1. [tx-control-service-local][4] :- A purely local transaction control service implementation. This can be 
+1. [tx-control-service-local][5] :- A purely local transaction control service implementation. This can be 
 used with any resource-local capable ResourceProvider
 
-2. [tx-control-service-xa][5] :- An XA-capable transaction control service implementation based on the 
+2. [tx-control-service-xa][6] :- An XA-capable transaction control service implementation based on the 
 Geronimo Transaction Manager. This can be used with XA capable resources, or with local resources. 
 Local resources will make use of the last-participant gambit.
 
-3. [tx-control-provider-jdbc-local][6] :- A JDBC resource provider that provides connection pooling and
+3. [tx-control-provider-jdbc-local][7] :- A JDBC resource provider that provides connection pooling and
 that can integrate with local transactions. The JDBCConnectionProviderFactory service may be used 
 directly, or a service may be configured using the _org.apache.aries.tx.control.jdbc.local_ pid
 
-4. [tx-control-provider-jdbc-xa][7] :- A JDBC resource provider that provides connection pooling and 
+4. [tx-control-provider-jdbc-xa][8] :- A JDBC resource provider that provides connection pooling and 
 that can integrate with local or XA transactions. The JDBCConnectionProviderFactory service may be 
 used directly, or a service may be configured using the _org.apache.aries.tx.control.jdbc.xa_ pid
 
-5. [tx-control-provider-jpa-local][8] :- A JPA resource provider that can integrate with local transactions. 
+5. [tx-control-provider-jpa-local][9] :- A JPA resource provider that can integrate with local transactions. 
 The JPAEntityManagerProviderFactory service may be used directly, or a service may be configured using 
 the _org.apache.aries.tx.control.jpa.local_ pid. The implementation can also provide connection pooling 
 if required
 
-6. [tx-control-provider-jpa-xa][9] :- A JDBC resource provider that integrates with XA transactions. 
+6. [tx-control-provider-jpa-xa][10] :- A JDBC resource provider that integrates with XA transactions. 
 The JPAEntityManagerProviderFactory service may be used directly, or a service may be configured using 
 the _org.apache.aries.tx.control.jpa.xa_ pid. The implementation can also provide connection pooling 
 if required
@@ -93,9 +98,10 @@ attribute will be removed from the expor
   [1]: https://github.com/osgi/design/blob/master/rfcs/rfc0221/rfc-0221-TransactionControl.pdf
   [2]: tx-control/quickstart.html
   [3]: tx-control/index.html
-  [4]: tx-control/localTransactions.html
-  [5]: tx-control/xaTransactions.html
-  [6]: tx-control/localJDBC.html
-  [7]: tx-control/xaJDBC.html
-  [8]: tx-control/localJPA.html
-  [9]: tx-control/xaJPA.html
\ No newline at end of file
+  [4]: tx-control/spring-tx.html
+  [5]: tx-control/localTransactions.html
+  [6]: tx-control/xaTransactions.html
+  [7]: tx-control/localJDBC.html
+  [8]: tx-control/xaJDBC.html
+  [9]: tx-control/localJPA.html
+  [10]: tx-control/xaJPA.html
\ No newline at end of file

Modified: aries/site/trunk/content/modules/tx-control/quickstart.mdtext
URL: http://svn.apache.org/viewvc/aries/site/trunk/content/modules/tx-control/quickstart.mdtext?rev=1744756&r1=1744755&r2=1744756&view=diff
==============================================================================
--- aries/site/trunk/content/modules/tx-control/quickstart.mdtext (original)
+++ aries/site/trunk/content/modules/tx-control/quickstart.mdtext Fri May 20 15:20:46 2016
@@ -63,13 +63,14 @@ methods can be used to ensure that a _No
 
 Simple scope management is perfect in most situations, but you may also wish to read about
 [more advanced scope control techniques][1] or [exception management][2] once you've mastered the basics.
+There are also some things to consider if you're [migrating from Spring or Java EE][3].
 
 ##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][3].
+needed you can [make your own ResourceProvider][4].
 
 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
@@ -127,4 +128,5 @@ The transactionality and lifecycle of th
 
   [1]: advancedScopes.html
   [2]: exceptionManagement.html
-  [3]: advancedResourceProviders.html
\ No newline at end of file
+  [3]: spring-tx.html
+  [4]: advancedResourceProviders.html
\ No newline at end of file

Added: aries/site/trunk/content/modules/tx-control/spring-tx.mdtext
URL: http://svn.apache.org/viewvc/aries/site/trunk/content/modules/tx-control/spring-tx.mdtext?rev=1744756&view=auto
==============================================================================
--- aries/site/trunk/content/modules/tx-control/spring-tx.mdtext (added)
+++ aries/site/trunk/content/modules/tx-control/spring-tx.mdtext Fri May 20 15:20:46 2016
@@ -0,0 +1,230 @@
+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.
+
+#Migrating from declarative transactions
+
+Many popular application containers, such as Spring or Java EE, offer declarative transaction management.
+Specifically, the container offers a model where transaction boundaries are defined using metadata, usually as
+annotations on public methods.
+
+## The Basics
+
+A typical transactional method in a declarative model might look like this:
+
+    @Transactional
+    public Long getCustomerId(String email) {
+        // Some business logic in here...
+    }
+
+Using Transaction control the same thing would look like:
+
+    public Long getCustomerId(String email) {
+        txControl.required(() -> {
+                // Some business logic in here...
+            });
+    }
+
+The main change is that the transactions have moved from being metadata defined, and started by the container,
+to being code defined and started by the Transaction Control service. This gives several significant advantages.
+
+## The Scoping Problem
+
+When using method-level metadata to define transaction boundaries it is not possible to manage transactions
+on a finer level. This makes it difficult to suspend or nest transactions unless you create a new method to hold
+the extra logic.
+
+### A Simple Example
+
+If we want to write an audit message it usually needs to occur in a new transaction, as typically it should persist
+even if the overall action fails. In a declarative model this requires a separate method with a new boundary,
+even if the audit function is a private implementation detail of the Object.
+
+    @Transactional
+    public void changePassword(String email, String password) {
+
+        auditPasswordChangeAttempt(email);
+    
+        // Some business logic in here...
+    } 
+    
+    @Transactional(REQUIRES_NEW)
+    public void auditPasswordChangeAttempt(String email) {
+        // One line to write the audit message
+    } 
+
+With transaction control there is no need to create a method just for the internal audit function.
+
+ @Transactional
+    public void changePassword(String email, String password) {
+        
+        txControl.required(() -> {
+
+                txControl.requiresNew(() -> {
+                        // One line to write the audit message
+                    });
+
+                // Some business logic in here...
+            });
+    } 
+  
+
+## The Proxy Problem
+
+The Proxy problem is a rather insidious issue that affects declarative transactions, and it is a result of how they
+are implemented. If bytecode weaving is used to directly add transactional behaviour to an object then it will
+always work the same way. Most solutions, however, do not use bytecode weaving, but instead use a proxy
+pattern. When a call is made on the proxy the proxy will perform any necessary transaction management
+before and after delegating the call to the real object. This works well, except if the object makes any internal
+method calls.
+
+In the general case proxying is unsafe because you cannot rely on a method's metadata to decide what 
+transaction state will exist when it is called!
+
+### Examples of the Proxy Problem
+
+The following examples are all based on real code migrated from Spring to Transaction Control.
+
+#### A Simple Example
+
+    AbstractPersistenceDataManagerImpl {
+
+        @Transactional(propagation = SUPPORTS, readOnly = true)
+        public <T> T search(Class<T> entityClass, Object pk, Object params) {
+            return (T) find(entityClass, pk, params);
+        }
+
+        @Transactional(readOnly = true)
+        public UniWorksSuperDBEntity find(Class entityClass, Object pk, Object params) {
+            return (UniWorksSuperDBEntity) em.find(entityClass, pk);
+        }
+    }
+
+In this case the <code>search</code> method does not require a transaction, but delegates to the 
+<code>find</code> method which does. If proxying is used then the <code>find</code> method will
+sometimes run in a transaction and sometimes not. On the other hand, if weaving is used then the
+<code>find</code> method will *always* run under a transaction This may seem innocuous, but it 
+can cause big problems. We always want to be certain about where a transaction will start and stop!
+
+#### Extending the Simple Example
+
+The following type is part of the same project as the previous example, and interacts with it.
+
+    AbstractDataManager {
+
+        @Transactional(propagation = NOT_SUPPORTED, readOnly = true)
+        public UniWorksSuperDTO search(Object pk, Object params) {
+        
+            UniWorksSuperDBEntity entity = persistenceDataManager
+                    .search(getEntityClass(), createNewPKFromDTOPK(pk), null);
+
+            loadLinkedTablesTop(entity, params);
+        }
+
+        protected final void loadLinkedTablesTop(UniWorksSuperDBEntity entity, Object params) {
+            loadLinkedTables(entity, params);
+        }
+
+        @Transactional(readOnly = true)
+        public void loadLinkedTables(UniWorksSuperDBEntity entity, Object params) {
+            loadLinkedTablesGenerated(entity, params);
+            loadLinkedTransients(entity, params);
+        }
+    }
+
+Now lets imagine that a call comes in to the <code>search</code> method of this class from some client.
+
+##### Proxied
+
+ 1. The container proxy for the data manager halts any ongoing transaction due to the 
+<code>NOT_SUPPORTED</code> metadata, entering an undefined scope.
+ 2. The code calls search on the persistenceDataManager
+ 3. The container proxy for the persistence data manager does not start or stop a transaction due to the
+<code>SUPPORTS</code> scope.
+ 4. The code calls <code>find</code> on the persistenceDataManager, but without touching the proxy.
+ 5. The code accesses the entity outside a transaction
+ 6. The code returns the entity, and no transaction change is necessary
+ 7. The code calls loadLinkedTablesTop, which calls loadLinkedTables. No proxy is touched therefore no 
+transaction is started.
+8. The Tables are populated with data from the entity. Lazy loading is possible as the entity is still attached.
+
+##### Woven
+
+ 1. The weaving code for the data manager halts any ongoing transaction due to the 
+<code>NOT_SUPPORTED</code> metadata, entering an undefined scope.
+ 2. The code calls search on the persistenceDataManager
+ 3. The weaving code for the persistence data manager does not start or stop a transaction due to the
+<code>SUPPORTS</code> scope.
+ 4. The code calls <code>find</code> on the persistenceDataManager, at this point the weaving code starts
+a transaction.
+ 5. The code accesses the entity inside the transaction
+ 6. The code returns the entity, and the transaction completes. This detaches the entity and prevents lazy loading.
+ 7. The code calls loadLinkedTablesTop, which calls loadLinkedTables. The weaving code starts a new 
+transaction.
+ 8. The Code fails as the entity is not able to access its lazily loaded data.
+
+### Strategies for Managing Transaction States
+
+Ensuring consistency is vital when writing code that uses transactions. It is therefore usually a good idea to 
+ensure that any reused code is captured in a private method, and that it asserts the correct transaction state
+before it begins.
+
+    AbstractDataManager {
+
+        public UniWorksSuperDTO search(Object pk, Object params) {
+        
+            txControl.build().readOnly().notSupported(() -> {
+                    UniWorksSuperDBEntity entity = persistenceDataManager
+                            .search(getEntityClass(), createNewPKFromDTOPK(pk), null);
+
+                    loadLinkedTablesTop(entity, params);
+                    return entity;
+            }
+        }
+
+        protected final void loadLinkedTablesTop(UniWorksSuperDBEntity entity, Object params) {
+            loadLinkedTables(entity, params);
+        }
+
+        public void loadLinkedTables(UniWorksSuperDBEntity entity, Object params) {
+            txControl.build().readOnly().required(() -> {
+                    loadLinkedTables(entity, params);
+                });
+        }
+
+        /**
+         * This method does not need a transaction, but does need a scope
+         */
+        private void loadLinkedTablesInternal(UniWorksSuperDBEntity entity, Object params) {
+            assert txControl.activeScope();
+
+            loadLinkedTablesGenerated(entity, params);
+            loadLinkedTransients(entity, params);
+        }
+    }
+
+Writing code in this way ensures that even when a mixture of transactional and non transactional actions are
+needed, there will always be a consistent expectation of the transaction scope in each method.
+
+## Exception management
+
+The final significant difference between declarative models and the Transaction Control Service is in how much
+work your application code needs to do when managing exceptions. More detail about managing exceptions
+[is available here][1].
+
+
+  [1]: exceptionManagement.html
\ No newline at end of file

Propchange: aries/site/trunk/content/modules/tx-control/spring-tx.mdtext
------------------------------------------------------------------------------
    svn:eol-style = native