Pour ceux qui ne connaissent pas la puissance de JPA, il y a un tutorial intéressant (en français) par ici !

Le problème dans un projet JavaEE est que la configuration de la PersistenceUnit se fait au déployement. A la base le fichier de configuration (persistence.xml) se présente de la manière suivante (je suis sous NetBeans 6.1) :

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="myPersistenceUnit" transaction-type="JTA">
    <jta-data-source>myDB</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>

Et il est très simple de l'utiliser au sein d'un SessionBean :

//import...
@Stateless
public class MySessionBean
{
    @PersistenceContext
    private EntityManager em;
 
    public void myFunction()
    {
            //...
            em.persist(myEntity);
            //...
    }
}

A cette étape, rien de bien sorcier. Les choses se compliquent lorsqu'une deuxième PersistenceUnit est définie au sein du fichier de configuration :

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="myPersistenceUnit" transaction-type="JTA">
    <jta-data-source>myDB</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
  <persistence-unit name="secondPersistenceUnit" transaction-type="JTA">
    <jta-data-source>secondDB</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>

Lors du redéployement, l'erreur suivante est balancée par NetBeans :

Deploying application in domain failed; Could not resolve a persistence unit corresponding to the persistence-context-ref-name [MySessionBean/em] in the scope of the module called []. Please verify your application.
Deployment error:
The module has not been deployed.
See the server log for details.
        at org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment.deploy(Deployment.java:166)
        at org.netbeans.modules.j2ee.ant.Deploy.execute(Deploy.java:104)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
        at sun.reflect.GeneratedMethodAccessor66.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
        at org.apache.tools.ant.Task.perform(Task.java:348)
        at org.apache.tools.ant.Target.execute(Target.java:357)
        at org.apache.tools.ant.Target.performTasks(Target.java:385)
        at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
        at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
        at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
        at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
        at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:277)
        at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:460)
        at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:151)

Un message super expressif n'est-ce pas ? En développant sur JavaEE, je trouve que c'est une des choses les plus pénibles : les messages d'erreur qui ne veulent rien dire ! Ce qui se passe ici en fait, c'est que le serveur n'est pas capable de choisir dynamiquement quelle PersistenceUnit il doit attributer à la variable 'em'. Il est donc très facile de corriger cela :

//import...
@Stateless
public class MySessionBean
{
    @PersistenceContext(unitName="myPersistenceUnit")
    private EntityManager em;
 
    public void myFunction()
    {
            //...
            em.persist(myEntity);
            //...
    }
}

Et tout refonctionne normalement. J'en arrive maintenant au problème évoqué plus haut : le choix de la PersistenceUnit est fait au déployement. Dans un projet récent, l'idée était de pouvoir changer de PersistenceUnit dynamiquement au runtime. L'information n'est pas facile à trouver et nécessite un petit remodelage de la classe !

Tout d'abord, il faut lister les PersistenceUnit au début de la classe comme ceci :

@PersistenceContexts({
   @PersistenceContext(name="persistence/myPU1", unitName="myDB"),
   @PersistenceContext(name="persistence/myPU2", unitName="secondDB")
})

Et il est ensuite possible de récupérer un EntityManager correspondant à une PersistenceUnit définie via une requête JNDI :

EntityManager em1 = (EntityManager) new InitialContext().lookup("java:comp/env/persistence/myPU1");
EntityManager em2 = (EntityManager) new InitialContext().lookup("java:comp/env/persistence/myPU2");

Il ne reste plus qu'a encapsuler cela dans une méthode et quelques autres fioritures pour pouvoir dynamiquement changer de base de donnée au runtime (merci à Raphael Tagliani pour le bout de code) ! :)