You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by rs...@apache.org on 2015/06/01 12:07:22 UTC

deltaspike git commit: DELTASPIKE-816 document usage of multiple entity-managers

Repository: deltaspike
Updated Branches:
  refs/heads/master f32841270 -> 087bb799a


DELTASPIKE-816 document usage of multiple entity-managers


Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/087bb799
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/087bb799
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/087bb799

Branch: refs/heads/master
Commit: 087bb799ac8afc1a5c60986a31e11eb02db0a1e1
Parents: f328412
Author: Ron Smeral <rs...@apache.org>
Authored: Mon Jun 1 11:34:45 2015 +0200
Committer: Ron Smeral <rs...@apache.org>
Committed: Mon Jun 1 11:57:07 2015 +0200

----------------------------------------------------------------------
 documentation/src/main/asciidoc/data.adoc |   6 +-
 documentation/src/main/asciidoc/jpa.adoc  | 239 ++++++++++++++-----------
 2 files changed, 139 insertions(+), 106 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/087bb799/documentation/src/main/asciidoc/data.adoc
----------------------------------------------------------------------
diff --git a/documentation/src/main/asciidoc/data.adoc b/documentation/src/main/asciidoc/data.adoc
index fefbb3c..57355b1 100644
--- a/documentation/src/main/asciidoc/data.adoc
+++ b/documentation/src/main/asciidoc/data.adoc
@@ -222,7 +222,7 @@ methods, it is not possible to simply add the annotation there. It needs
 to go on each concrete repository. The same is not true if a base class
 is introduced, as we see in the next chapter.
 
-===== The `AbstractEntityRepository` Class
+===== The AbstractEntityRepository Class
 
 This class is an implementation of the `EntityRepository` interface and
 provides additional functionality when custom query logic needs also to
@@ -264,7 +264,7 @@ public interface PersonRepository implements Deactivatable{
 }    
 ----------------------------------------
 
-=== Using Multiple `EntityManager`
+=== Using Multiple EntityManagers
 
 While most applications will run just fine with a single
 `EntityManager`, there might be setups where multiple data sources are
@@ -297,7 +297,7 @@ possible to create something like a base `CrmRepository` interface with
 the `@EntityManagerConfig` and then extending / implementing this
 interface.
 
-=== Other `EntityManager` Methods
+=== Other EntityManager Methods
 
 While the `EntityRepository` methods should cover most interactions
 normally done with an `EntityManager`, for some specific cases it might

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/087bb799/documentation/src/main/asciidoc/jpa.adoc
----------------------------------------------------------------------
diff --git a/documentation/src/main/asciidoc/jpa.adoc b/documentation/src/main/asciidoc/jpa.adoc
index f7d8943..e096ba4 100644
--- a/documentation/src/main/asciidoc/jpa.adoc
+++ b/documentation/src/main/asciidoc/jpa.adoc
@@ -46,20 +46,22 @@ For CDI 1.0 (or DeltaSpike v1.1.0 and earlier together with CDI 1.1+), you must
 
 == @Transactional
 
-This annotation is an alternative to transactional EJBs which allows to
-execute a method within a transaction. Before it is possible to start
+This annotation is an alternative to transactional EJBs and enables the execution
+of a method within a transaction. Before it is possible to start
 using the annotation, it is required to implement a CDI producer for an
 `EntityManager` and it is needed to inject the `EntityManager` in the
 bean which uses `@Transactional`. As shown later on, it is also possible
-to use multiple qualifiers for using different `EntityManager`s.
+to use multiple qualifiers for using different EntityManagers.
+
+=== Basic usage
 
 The following example shows a simple producer for an `EntityManager` and
-the corresponding dispose-method. Producing it as request scoped bean
-means that the dispose method will be called on finishing the request.
-As an alternative it is possible to use a special scope called
-`@TransactionScoped` provided by the same DeltaSpike module.
+the corresponding disposer method. Producing it as request scoped bean
+means that the disposer method will be called on finishing the request.
+Alternatively it is possible to use a special scope called
+<<__transactionscoped, `@TransactionScoped`>>.
 
-.Producer for the Default EntityManager (**no EE-Server**)
+.Producer for the Default EntityManager (non-EE server)
 [source,java]
 ----------------------------------------------------------------------------
 //...
@@ -86,7 +88,7 @@ public class EntityManagerProducer
 }
 ----------------------------------------------------------------------------
 
-.Producer for the Default EntityManager (**EE-Server**)
+.Producer for the Default EntityManager (EE server)
 [source,java]
 -----------------------------------------------------------------------
 @ApplicationScoped
@@ -116,7 +118,7 @@ public class EntityManagerProducer
 The following examples show how to use the `EntityManager` produced by
 the example above.
 
-.Beans with Transactional Method
+.Bean with a Transactional Method
 [source,java]
 ----------------------------------------
 //...
@@ -171,58 +173,141 @@ public class TransactionalBean
 }
 ----------------------------------------
 
-Besides such simple usages, it is also supported to use qualifiers to
-access multiple persistence-units in parallel. The default qualifier for
-`@Transactional` is `@Any`. Therefore a transaction for every injected
-entity manager will be started. The example afterwards shows how to
-change this default behaviour.
+=== Multiple EntityManagers
+
+The default qualifier for `@Transactional` is `@Any` whereby a transaction gets started for every injected entity manager. Besides such simple usages, it is also possible to access multiple persistence units in parallel using qualifiers. 
+
+First, the EntityManagers or EntityManagerFactories must be obtained from the JPA subsystem, then EntityManagers must be made available as CDI beans and finally injected into `@Transactional` beans for usage.
+
+==== Obtaining EntityManagers from JPA
 
-.Producer for Multiple Entity Managers (+ Usage)
+In EE managed environments the EntityManager can be obtained directly or through an EntityManagerFactory using standard JPA annotations `@PersistenceContext` for an EntityManager or `@PersistenceUnit` for an EntityManagerFactory.
+
+.JPA Managed EntityManager
 [source,java]
-------------------------------------------------------------------------------------------
-//...
-public class EntityManagerProducer
-{
+----
+public class EntityManagerProducer {
+
     @PersistenceContext(unitName = "firstDB")
     private EntityManager firstEntityManager;
 
     @PersistenceContext(unitName = "secondDB")
     private EntityManager secondEntityManager;
+    
+    // ...
+}
+----
+
+An alternative for non-EE environments is available through DeltaSpike's `@PersistenceUnitName` qualifier allowing to inject EntityManagerFactories.
 
+.Unmanaged EntityManagerFactory
+[source,java]
+----
+public class EntityManagerProducer {
+
+    @Inject
+    @PersistenceUnitName("puA")
+    private EntityManagerFactory emfA;
+
+    @Inject
+    @PersistenceUnitName("puB")
+    private EntityManagerFactory emfB;
+    
+    // ...
+}
+----
+
+Obtaining an EntityManager from an EntityManagerFactory is just a matter of calling `emfA.createEntityManager()`.
+
+==== Producing Multiple EntityManagers
+There are several ways to make multiple entity managers available for use in `@Transactional` methods, each suitable for a different situation.
+
+The simplest method employs a producer and a disposer for each EntityManager.
+
+.Deciding using qualifiers
+[source,java]
+----
+public class EntityManagerProducer {
+    
+    // ...entity managers or factories injected here
+    
     @Produces
-    @First
-    @RequestScoped
-    protected EntityManager createFirstEntityManager()
+    @RequestScoped // or other
+    @DbA //custom qualifier annotation
+    public EntityManager createEntityManagerA()
     {
-        return this.firstEntityManager;
+        return emfA.createEntityManager();
     }
 
-    protected void closeFirstEntityManager(@Disposes @First EntityManager entityManager)
+    public void closeEmA(@Disposes @DbA EntityManager em)
     {
-        if (entityManager.isOpen())
-        {
-            entityManager.close();
-        }
+        em.close();
     }
 
     @Produces
-    @Second
     @RequestScoped
-    protected EntityManager createSecondEntityManager()
+    @DbB //custom qualifier annotation
+    public EntityManager createEntityManagerB()
     {
-        return this.secondEntityManager;
+        return emfB.createEntityManager();
     }
 
-    protected void closeSecondEntityManager(@Disposes @Second EntityManager entityManager)
+    public void closeEmB(@Disposes @DbB EntityManager em)
     {
-        if (entityManager.isOpen())
-        {
-            entityManager.close();
+        em.close();
+    }
+    
+}
+----
+
+If there's the need to decide dynamically on which EntityManager should be used when it's possible to use the standard CDI facility of `InjectionPoint` to get information about the injection points and produce different EntityManagers with just one producer method.
+
+.Deciding using InjectionPoint
+[source,java]
+----
+public class EntityManagerProducer {
+
+    // ...entity managers or factories injected here
+
+    @Produces
+    protected EntityManager createEntityManager(InjectionPoint injectionPoint)
+    {
+        CustomQualifier customQualifier = injectionPoint.getAnnotated().getAnnotation(CustomQualifier.class);
+        return selectEntityManager(customQualifier); //selects firstEntityManager or secondEntityManager based on the details provided by CustomQualifier
+    }
+}
+----
+
+The information necessary to make the decision about the EntityManager appropriate for the current situation and injection point may be available elsewhere, for example in a custom context.
+
+.Deciding using anything else
+[source,java]
+----
+public class EntityManagerProducer {
+
+    // ...entity managers or factories injected here
+    
+    @Inject
+    private CustomDatabaseContext customDatabaseContext;
+
+    @Produces
+    protected EntityManager createEntityManager()
+    {
+        if (customDatabaseContext.usePrimaryDb()) {
+            return firstEntityManager;
         }
+        return secondEntityManager;
     }
 }
+----
 
-//...
+==== Using transactions with multiple EntityManagers
+
+One use case for multiple EntityManagers is their usage in nested transactions. When a transactional method is called from within a transactional method, it joins the existing transaction.
+
+.Nested transactions with multiple EntityManagers
+[source,java]
+----
 public class FirstLevelTransactionBean
 {
     @Inject
@@ -239,7 +324,6 @@ public class FirstLevelTransactionBean
     }
 }
 
-//...
 public class NestedTransactionBean
 {
     @Inject
@@ -251,12 +335,11 @@ public class NestedTransactionBean
         //...
     }
 }
-------------------------------------------------------------------------------------------
+----
 
-The following example shows how to use only the specified
-`EntityManager`/s
+It's also easy to use multiple EntityManagers in the same bean in different transactional methods. By default, a `@Transactional` method would enroll all of the EntityManagers in the transaction. By using `@Transactional(qualifier=...)` it's easy to choose individual EntityManagers for each transactional method.
 
-.Activating Entity Managers Manually
+.Selecting individual EntityManagers for a transactional method
 [source,java]
 -----------------------------------------------------------
 public class MultiTransactionBean
@@ -271,64 +354,16 @@ public class MultiTransactionBean
     private @Second EntityManager secondEntityManager;
 
     @Transactional(qualifier = Default.class)
-    public void executeInDefaultTransaction()
-    {
-    }
+    public void executeInDefaultTransaction() {...}
 
     @Transactional(qualifier = First.class)
-    public void executeInFirstTransaction()
-    {
-    }
-
-    @Transactional(qualifier = Second.class)
-    public void executeInSecondTransaction()
-    {
-    }
+    public void executeInFirstTransaction() {...}
 
     @Transactional(qualifier = {First.class, Second.class})
-    public void executeInFirstAndSecondTransaction()
-    {
-    }
+    public void executeInFirstAndSecondTransaction() {...}
 }
 -----------------------------------------------------------
 
-All examples also work with nested calls. In the following example the
-transaction handling is done on the entry point (after
-FirstLevelTransactionBean#executeInTransaction).
-
-.Joining Existing Transaction in Nested Call
-[source,java]
-----------------------------------------------------------
-//...
-public class FirstLevelTransactionBean
-{
-    @Inject
-    private EntityManager entityManager;
-
-    @Inject
-    private NestedTransactionBean nestedTransactionBean;
-
-    @Transactional
-    public void executeInTransaction()
-    {
-        this.nestedTransactionBean.executeInTransaction();
-    }
-}
-
-//...
-public class NestedTransactionBean
-{
-    @Inject
-    private EntityManager entityManager;
-
-    @Transactional
-    public void executeInTransaction()
-    {
-        //...
-    }
-}
-----------------------------------------------------------
-
 The final transaction handling for all `EntityManager` s is also done
 after the outermost transactional method if `NestedTransactionBean` uses
 a different `EntityManager`. So it is possible to catch an exception in
@@ -341,13 +376,11 @@ immediate rollback.
 transaction started by `@Transactional`. Besides other beans you can use
 this scope for the `EntityManager` itself. That means the
 `EntityManager` will be closed after leaving the method annotated with
-`@Transactional`.
+`@Transactional`. 
 
-.Producer for the Default EntityManager which should be Used Only for One
-Transaction
+.Using a transaction-scoped EntityManager
 [source,java]
 ----------------------------------------------------------------------------
-//...
 public class EntityManagerProducer
 {
     //or manual bootstrapping
@@ -389,7 +422,7 @@ conversation scoped `EntityManager` as it is. We *do not* recommend this approac
 However, if you really need this approach to avoid calling `#merge` for
 your detached entities, it is pretty simple to add this functionality.
 
-.Usage of a Simple `ExtendedEntityManager`
+.Usage of a Simple extended EntityManager
 [source,java]
 ------------------------------------
 @Inject
@@ -400,7 +433,7 @@ As you see the usage is the same. You *do not* have to use
 `ExtendedEntityManager` at the injection point. It is just needed in the
 producer-method:
 
-.Producer for the Default Extended-`EntityManager` (**no EE-Server**)
+.Producer for an extended EntityManager (non-EE server)
 [source,java]
 ------------------------------------------------------------------------------------
 //...
@@ -427,7 +460,7 @@ public class ExtendedEntityManagerProducer
 }
 ------------------------------------------------------------------------------------
 
-.Producer for the Default Extended-`EntityManager` (**EE-Server**)
+.Producer for an extended EntityManager (EE server)
 [source,java]
 ------------------------------------------------------------------------------------------
 @ApplicationScoped
@@ -454,7 +487,7 @@ public class ExtendedEntityManagerProducer
 }
 ------------------------------------------------------------------------------------------
 
-.Implementation of a Simple `ExtendedEntityManager`
+.Implementation of a simple extended EntityManager
 [source,java]
 -------------------------------------------------------------------------
 @Typed()
@@ -508,8 +541,8 @@ in the beans.xml which is called
 </beans>
 ----------------------------------------------------------------------------------------------------
 
-If you have multiple persistence-units and you have to use both
-transaction-types or the settings for development have to be different
+If you have multiple persistence units and you have to use both
+transaction types or the settings for development have to be different
 than the production settings, you can use
 `org.apache.deltaspike.jpa.impl.transaction.EnvironmentAwareTransactionStrategy`
 instead.