IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JPA Java Discussion :

Comment avoir des Entity en Persistance continue ?


Sujet :

JPA Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut Comment avoir des Entity en Persistance continue ?
    Bonjour,

    J’ai crée une application qui gère la persistance avec JPA. J’ai géré facilement la sauvegarde à la demande (action save -> model enregistré en base).

    Par contre, j’ai certaines Entity qui sont critiques, et qui ont besoin d’être sauvegardé en continue (toujours synchro avec la base).


    Après quelques recherches, j’ai vu que l'on pouvait jouer sur la propriété EXTENDED du persistence context. Mais apparemment, l'entity manager doit être stocké dans un Stateful session bean.
    Donc il faudrait que je construise un DAO comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    @Stateful //Auparavant, mon DAO était Stateless
    public class JPADAO {
     
    	@PersistenceContext(type = PersistenceContextType.EXTENDED, name = ATMprojectV2Bean.ATMPROJECT_V2)
    	private EntityManager emExtended;
    ...
    }
    Et c’est tout ? Toute mes Entity qui seront gérés par cet Entity Manager seront automatiquement sauvegardé en base à chaque commit de la transaction courante ?

    Quelqu’un a un avis sur la façon de faire ?

    Merci d’avance,

    Samuel

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 74
    Par défaut
    Citation Envoyé par sam69 Voir le message
    Bonjour,

    Par contre, j’ai certaines Entity qui sont critiques, et qui ont besoin d’être sauvegardé en continue (toujours synchro avec la base).
    Il n'y a aucun moyen de t'assurer que les données d'un entitée sont synchro avec les données de la base. le PC Extended ne t'aidera pas pour cela...

    La seule chose que tu puisse faire est de limiter les risques de violations de l'intégrité des données en utilisant les verrou optimistes (@Version) cela te permet de vérifier qu'au moment de la sauvegarde les modifications sur une entité, les données de cet enregistrement n'ont pas été modifié depuis leur lecture (et donc que tu es toujours à jour).

    Tu peux toujours rafraîchir une entité avec em.refresh(o); mais rien ne te permet d'affirmer que 2millième de secondes plus tard, l'enrigisrement n'a pas été modifié.... donc le refresh limite seuelemnt le pb

    Après quelques recherches, j’ai vu que l'on pouvait jouer sur la propriété EXTENDED du persistence context. Mais apparemment, l'entity manager doit être stocké dans un Stateful session bean.
    Donc il faudrait que je construise un DAO comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    @Stateful //Auparavant, mon DAO était Stateless
    public class JPADAO {
     
    	@PersistenceContext(type = PersistenceContextType.EXTENDED, name = ATMprojectV2Bean.ATMPROJECT_V2)
    	private EntityManager emExtended;
    ...
    }
    Et c’est tout ? Toute mes Entity qui seront gérés par cet Entity Manager seront automatiquement sauvegardé en base à chaque commit de la transaction courante ?

    Quelqu’un a un avis sur la façon de faire ?

    Merci d’avance,

    Samuel

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    Merci denisjava pour ta réponse.

    En fait il n'y a que moi qui modifie la base. C'est juste une histoire de sauvegarde en continue pour permettre de redémarrer le server après une panne, et de retrouver les dernières données enregistrés.
    Donc je ne pense pas qu'il y a besoin de verrou optimistes.

    J'ai simplement besoin que mes Entity soit sauvegardés automatiquement (sans appeller em.persist(myEntity) ) à chaque fin de transaction (JTA).

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    J'ai fait un petit programme de test pour vérifier le fonctionnement des EXTENDED PersistenceContext, mais cela ne tient pas ses promesses.
    Lorsque je suis dans une autre transaction, les Entity managés par l'EntityManagerExtended ne sont pas sauvegardés en base automatiquement.

    J'aimerais que mes Entity soit sauvegardées automatiquement dès lors qu'elles sont modifiées à l'interieur de n'importe quelle transaction pouvant être en dehors du DAO.
    Je n'arrive pas à trouver des infos claires, et j'ai l'impression que mes besoins sortent un peu des fonctionnalités JEE

    Voici mon code de test, si quelqu'un a des suggestions...

    Mon statefull session bean qui fait office de DAO et qui contient extended EntityManager:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    @Remote({ SimpleJPADAOBeanInterface.class })
    @RemoteBinding(jndiBinding = "JPADAO")
    @Stateful
    @TransactionManagement(TransactionManagementType.CONTAINER)
    public class SimpleJPADAOBean implements SimpleJPADAOBeanInterface{
     
    	@PersistenceContext(type = PersistenceContextType.EXTENDED, unitName = "testJPA2")
    	private EntityManager emExtended;
     
    	private MyEntity myEntity;
     
    	public SimpleJPADAOBean() {
    		super();
    	}
    	public void createEntity() {
     
    		myEntity = new MyEntity();
    	}
    	public void persistEntity() {
    		emExtended.persist(myEntity);
    	}
    	public void updateEntity() {
    		myEntity.setStr(myEntity.getStr() + "_updated");
    	}
    	public MyEntity getEntity() {
    		return myEntity;
    	}
    }
    Et mon stateless qui fait office de client webservice pour tester le DAO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    @Stateless
    @Remote( { SimpleFronBeantStatelessInterface.class })
    @WebService(serviceName = "testJPA2", targetNamespace = "http://service."+ "testJPA2" + "/jaws")
    @WebContext(contextRoot = "testJPA2", urlPattern = "/" + "testJPA2")
    public class SimpleFrontBeanStateless implements SimpleFronBeantStatelessInterface{
    	public SimpleFrontBeanStateless() {
     
    	}
    	@WebMethod
    	public void startTest() {
    		try {
    			SimpleJPADAOBeanInterface dao = SimpleDAOManager.getInstance().getDao();
    			dao.createEntity();
    			dao.persistEntity();
    //			dao.updateEntity();
    		} catch(Exception e) {
    			e.printStackTrace();
    		}
    	}
     
    	@WebMethod
    	@TransactionAttribute(TransactionAttributeType.REQUIRED)
    	public void update() {
    		SimpleJPADAOBeanInterface dao = SimpleDAOManager.getInstance().getDao();
    		MyEntity entity = dao.getEntity();
    		entity.setStr(entity.getStr() + "_updated");
    	}
    }
    Lors de l'appel d'update, l'Entity managés avec un context étendu n'est pas mis à jour, et pourtant, on est dans une transaction (@TransactionAttribute)

    Merci d'avance pour votre aide !

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 74
    Par défaut
    Avant toute chose je ne sais pas si l'injection de 2 PC (un de type trasncation et de type etendue) est quelques chose qui est sensé (ou en tout cas, la spec ne mentionne rien à ce sujet à ma connaissance). Aussi, afin d'éviter les effets de bord, je t'invite à n'injecter qu'un seul PC dans ton staful.

    tu peux montrer le code de ton DAOManager stp ?

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    Je viens de simplifier l'exemple (edit), avec qu'un entityManager.

    Voici le code de mon DAOMAnager, qui n'est q'un singleton stockant le DAO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    public class SimpleDAOManager {
     
    	private SimpleJPADAOBeanInterface dao;
     
    	private static SimpleDAOManager instance;
     
    	public synchronized static SimpleDAOManager getInstance() {
    		if (instance == null) {
    			instance = new SimpleDAOManager();
    		}
    		return instance;
    	}
     
    	protected SimpleDAOManager() {
    		try {
    			Context ctx = new InitialContext();
    			Object lookupObject = ctx.lookup("JPADAO");
    			dao = (SimpleJPADAOBeanInterface)lookupObject;
    		} catch (NamingException e) {
    			e.printStackTrace();
    		}
     
    	}
     
    	public SimpleJPADAOBeanInterface getDao() {
    		return dao;
    	}
     
    	public void setDao(SimpleJPADAOBeanInterface dao) {
    		this.dao = dao;
    	}
    }

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    Par contre, si au lieu de faire la modif de l'entity dans le Stateless Front, j'appel une méthode du DAO qui fait exactement la même chose cela fonctionne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	@WebMethod
    	@TransactionAttribute(TransactionAttributeType.REQUIRED)
    	public void update() {
    		SimpleJPADAOBeanInterface dao = SimpleDAOManager.getInstance().getDao();
    //		MyEntity entity = dao.getEntity();
    //		entity.setStr(entity.getStr() + "_updated");
    		dao.updateEntity();
    	}
    Il doit y avoir des Transactions différentes ? Je ne vois pas bien la différence en fait...

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 74
    Par défaut
    première remarque: mettre un dao en statique implique que tous les consomateurs de ton WS utiliseront le même qu ise verra injecter le meme entitymanager... donc pas bonne idée... mais cela n'explique pas ton pbx

    La réponse à ton problème est simple... (enfin j'espère ;-))
    Lorsque depuis ton stateless tu récupères un entité détaché (ben vi, ton stateful est remote, il serialize donc ton entité même s'ils sont dans la même machine virtuelle). Un objet sérializé est une duplication de ton objet initial et cette copie n'est pas attachée au contexte de peristance ! (ce qui justifie que quand tu appelles une métodes de ton stateful, cela fonctionne: tu modifies alors le bon objet, celui qui est attaché)...

    Donc il te suffit de déclarer ton stateful @Local, et ce sera alors du passage par référence et pas par valeur....


    Citation Envoyé par sam69 Voir le message
    Je viens de simplifier l'exemple (edit), avec qu'un entityManager.

    Voici le code de mon DAOMAnager, qui n'est q'un singleton stockant le DAO:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    public class SimpleDAOManager {
     
    	private SimpleJPADAOBeanInterface dao;
     
    	private static SimpleDAOManager instance;
     
    	public synchronized static SimpleDAOManager getInstance() {
    		if (instance == null) {
    			instance = new SimpleDAOManager();
    		}
    		return instance;
    	}
     
    	protected SimpleDAOManager() {
    		try {
    			Context ctx = new InitialContext();
    			Object lookupObject = ctx.lookup("JPADAO");
    			dao = (SimpleJPADAOBeanInterface)lookupObject;
    		} catch (NamingException e) {
    			e.printStackTrace();
    		}
     
    	}
     
    	public SimpleJPADAOBeanInterface getDao() {
    		return dao;
    	}
     
    	public void setDao(SimpleJPADAOBeanInterface dao) {
    		this.dao = dao;
    	}
    }

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    Merci beaucoup Denis !
    C'était bien le Remote le problème.
    J'ai mis mon StateFull en Local (je n'avais pas besoin du Remote en fait) et cela fonctionne bien comme je veux !

    Par contre, je ne comprend pas pourquoi ce n'est pas une bonne idée de stocker mon stateful dans un singleton. Je veux bien utiliser le même EntityManager pour tous mes appels de web service...

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 74
    Par défaut
    Citation Envoyé par sam69 Voir le message
    Merci beaucoup Denis !
    C'était bien le Remote le problème.
    J'ai mis mon StateFull en Local (je n'avais pas besoin du Remote en fait) et cela fonctionne bien comme je veux !
    A la bonne heure !


    Par contre, je ne comprend pas pourquoi ce n'est pas une bonne idée de stocker mon stateful dans un singleton. Je veux bien utiliser le même EntityManager pour tous mes appels de web service...
    Parceque le propre d'un stateful est de posséder un état dépendant d'un utilisateur précis... et en mettant la référence accesible via un singleton, cela signifie que tout consomateur de ton WS va accéder à ton ejb, et du coup ils vont tous partager le même EM. Je te le déconseille, potentiellement, tu auras des comportements étranges, pas visibles sur un test unitaire ne faisant intervenir un seul client....

    Plusieurs solutions sont ici envisageables: soit tu fais un WS stateful (beurk), qui utiilise la session HTTP qui stockera la référence de ton stateful en lieu et place de ton singleton: cela passe par une mise en oeuvre propriétaire dépendant de ta pile de WS (XFire, axis ou autre), il est possible que tu perde alors l'interop de ton WS (il te faudra la meme pile sur le client pour maintenit la sesion).
    Et l'autre possibilité: tu laisses ton WS stateless mais chacune des méthodes va faire le lookup vers l'ejb stateful en début et invoquer une méthode marquée @Remove à la fin de la méthode.C'est la solution que je préfère car ton stateful n'est stateful que pour des raisons techniques, et pas fonctionnelle...

    Hope this help.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Février 2003
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 30
    Par défaut
    Ok je vois. Je vais faire la methode du @Remove alors
    Merci encore !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 20
    Dernier message: 16/08/2006, 15h32
  2. Comment avoir des pages Web cryptées ?
    Par k_boy dans le forum Sécurité
    Réponses: 6
    Dernier message: 03/10/2005, 19h46
  3. Comment avoir des fenêtres parentes et enfants
    Par Invité dans le forum Agents de placement/Fenêtres
    Réponses: 6
    Dernier message: 20/09/2005, 11h53
  4. Comment avoir des information sur une BD?…
    Par kikimnet dans le forum Bases de données
    Réponses: 1
    Dernier message: 12/02/2005, 09h20
  5. Comment avoir des marges dans un TRichEdit ?
    Par nomdutilisateur dans le forum Composants VCL
    Réponses: 5
    Dernier message: 25/06/2004, 09h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo