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

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 164
    Points : 64
    Points
    64
    Par défaut JPA/Hibernate /@TransactionManagement => pas de transactions
    Bonjour,
    Je n'arrive pas à mettre en place les transactions dans un environnement JPA/Hibernate et annotations.
    Voici le contexte :
    J'ai choisi l'option TABLE pour générer la clé primaire de la table employee, cette clé primaire est bien générée, mais comme sa génération n'est pas prise dans la même transaction que celle de la création de la nouvelle occurrence de employee, j'ai une erreur duplicate primary key. Voici les détails de mon environnement de travail (il s'agit d'une reproduction sur un petit exemple et pas de l'application réelle, mais ce sera plus simple à comprendre) :
    IDE : NetBeans 11.2
    Type d'application : Enterprise Application nommée EmployeesJPA (ant) avec deux modules : EmployeesJPA-ejb et EmployeesJPA-war
    ORM : JPA avec implémentation sous Hibernate 4.3
    Base de données : MySql
    EJB Entity : Employee
    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
     
    @Entity
    @Table(name = "employee")
    @XmlRootElement
    @NamedQueries({
        @NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e"),
        @NamedQuery(name = "Employee.findByEmployeeId", query = "SELECT e FROM Employee e WHERE e.employeeId = :employeeId"),
        @NamedQuery(name = "Employee.findByName", query = "SELECT e FROM Employee e WHERE e.name = :name"),
        @NamedQuery(name = "Employee.findByManagerId", query = "SELECT e FROM Employee e WHERE e.managerId = :managerId"),
        @NamedQuery(name = "Employee.findByHiredate", query = "SELECT e FROM Employee e WHERE e.hiredate = :hiredate"),
        @NamedQuery(name = "Employee.findBySalary", query = "SELECT e FROM Employee e WHERE e.salary = :salary")})
    public class Employee implements Serializable {
     
        private static final long serialVersionUID = 1L;
        @Id
        @TableGenerator(name="EmployeePk", table="pkeys", pkColumnName="pkey_id",
                valueColumnName="pkey_val", pkColumnValue="EMPLOYEE", allocationSize=1)
        @GeneratedValue(strategy=GenerationType.TABLE, generator="EmployeePk")    
        @Basic(optional = false)
        @NotNull
        @Column(name = "employee_id")
        private Integer employeeId;
        . . .
    EJB Session EmployeeFacade
    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
    @LocalBean
    @TransactionManagement(TransactionManagementType.CONTAINER)
    public class EmployeeFacade {
        @PersistenceContext(unitName = "EmployeesJPA-ejbPU")
        private EntityManager em;
        @EJB
        JobFacade jobFacade;
        @EJB
        DepartmentFacade departmentFacade;
     
        @TransactionAttribute(TransactionAttributeType.REQUIRED)
        public void addEmployee(String name, Date hiredate, double salary, int jobId, int departmentId, int managerId) throws Exception {
            Employee employee = new Employee();
            try{
                Department department = departmentFacade.getDepartmentById(departmentId);
                Job job = jobFacade.getJobById(jobId);
                employee.setDepartment(department);
                employee.setJob(job);
                employee.setHiredate(hiredate);
                employee.setManagerId(managerId);
                employee.setName(name);
                em.persist(employee);
            }catch(Exception ex){
                throw ex;
            }
        }
    }
    Servlet SrvlEmployee
    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
     
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            String error = null;
            try {
                Date hiredate = Utilitaire.StrToDate("2020-02-01", "yyyy-MM-dd");
                BigDecimal salary = new BigDecimal(2000.00);
                employeeFacade.addEmployee("Smith", hiredate, salary, 2, 3, 4);
            } catch (Exception e) {
                error = Utilitaire.getExceptionCause(e);
            } finally {
                request.setAttribute("errorR", error);
                RequestDispatcher dsp = request.getRequestDispatcher("/index.jsp");
                dsp.forward(request, response);
            }
        }
    Table pkeys avant insertion :
    Nom : pkeyBefore.PNG
Affichages : 64
Taille : 7,2 Ko
    Table pkeys après insertion :
    Nom : pkeyAfter.PNG
Affichages : 65
Taille : 6,1 Ko
    L'id de la dernière occurrence de employee est 14.
    La trace des requêtes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Hibernate: select department0_.department_id as departme1_0_0_, department0_.dname as dname2_0_0_, department0_.location as location3_0_0_ from department department0_ where department0_.department_id=?
    Hibernate: select job0_.job_id as job_id1_2_0_, job0_.jobname as jobname2_2_0_ from job job0_ where job0_.job_id=?
    Hibernate: select pkey_val from pkeys where pkey_id = 'EMPLOYEE' for update
    Hibernate: update pkeys set pkey_val = ? where pkey_val = ? and pkey_id = 'EMPLOYEE'
    Hibernate: insert into employee (department_id, hiredate, job_id, manager_id, name, salary, employee_id) values (?, ?, ?, ?, ?, ?, ?)
    Le message d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SQL Error: 1062, SQLState: 23000
    Duplicate entry '14' for key 'PRIMARY'
    Précisions :
    - le même code sous EclipseLink fonctionne parfaitement !
    - j'ai essayé le REQUIRES_NEW à la place de REQUIRED, cela n'a rien changé.
    Voilà, si quelqu'un a une idée, je serais bien preneur !
    Merci d'avance pour votre aide.

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    novembre 2006
    Messages
    7 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 7 183
    Points : 9 306
    Points
    9 306
    Billets dans le blog
    1
    Par défaut
    D'après ce que j'ai lu sur le net, il semblerait qu'en mettant une valeur autre que 1 dans allocationSize corrige le problème...

    Mais bon, tu devrais utiliser un auto incrément géré par MySQL, beaucoup moins lourd.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 164
    Points : 64
    Points
    64
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    D'après ce que j'ai lu sur le net, il semblerait qu'en mettant une valeur autre que 1 dans allocationSize corrige le problème...

    Mais bon, tu devrais utiliser un auto incrément géré par MySQL, beaucoup moins lourd.
    Bonjour,
    Merci pour cette réponse, je vais tester. Pour ce qui concerne l'auto-incrémentation, j'ai effectivement fini par opter pour cette solution, mais elle n'est pas totalement satisfaisante.
    Est-ce qu'éventuellement tu aurais conservé les liens vers cette solution ?
    Je teste ta solution et reviens pour dire ce qu'il en est.
    A bientôt.

  4. #4
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    novembre 2006
    Messages
    7 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 7 183
    Points : 9 306
    Points
    9 306
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    La discussion que j'avais trouvé est ici.
    Et un autre article qui traite du sujet ici.

    Tu disais que la solution ne te convenais pas trop... J'imagine que tu aimerais avoir des numéros consécutifs ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 164
    Points : 64
    Points
    64
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Bonjour,

    La discussion que j'avais trouvé est ici.
    Et un autre article qui traite du sujet ici.

    Tu disais que la solution ne te convenais pas trop... J'imagine que tu aimerais avoir des numéros consécutifs ?
    Bonjour
    J'ai testé avec allocationSize=2, c'est du grand n'importe quoi, à la première insertion employee_id prend la valeur 28 (la dernière était 14 !), puis 29, 30, 31 ... pendant ce temps keys_id passe à 15, puis ne bouge pas puis 16, puis ne bouge pas ...
    J'y perds mon latin ;-)
    Je me demande si ce n'est pas l'implémentation JPA d'Hibernate qui est en cause parce que cela fonctionne parfaitement sous EclipsLink !
    La raison pour laquelle je voudrais utiliser l'option TABLE, c'est que j'aurais besoin de la clé générée pour enchaîner les insertions dans le cadre d'une seule transaction, exemple : Commande(commande_id), LigneCde (commande_id, article_id), Article(maj qtestock) ...
    Est-ce qu'éventuellement je peux te donner un lien vers mon exemple pour que tu puisses le tester ?

  6. #6
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    novembre 2006
    Messages
    7 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 7 183
    Points : 9 306
    Points
    9 306
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par clem_alain Voir le message
    Est-ce qu'éventuellement je peux te donner un lien vers mon exemple pour que tu puisses le tester ?
    Oui, aucun problème, d'autant que j'utilise Hibernate sur mon serveur, je pourrai plus facilement voir ce qui se passe.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 164
    Points : 64
    Points
    64
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Oui, aucun problème, d'autant que j'utilise Hibernate sur mon serveur, je pourrai plus facilement voir ce qui se passe.
    Voici le lien vers le Drive : https://drive.google.com/open?id=1xy...rzXxeZWd20SRZz
    Merci pour ton aide.

  8. #8
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    novembre 2006
    Messages
    7 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 7 183
    Points : 9 306
    Points
    9 306
    Billets dans le blog
    1
    Par défaut
    Bon, j'ai testé mais après avoir fait pas mal de modifications dans la structure du projet, je ne comprends pas le découpage que tu utilises

    J'ai utilisé la structure "normale" d'un projet EE, à savoir :
    - 1 projet EAR
    - 1 projet EJB
    - 1 projet Dynamic Web Module

    Je n'ai pas ici de base MySQL, du coup, la DB est une DB2/400, mais bon, ce n'est pas là qu'il devrait y avoir un problème.
    J'ai un serveur d'application Wildlfy-15, lequel utilise une version 5.3.7 d'Hibernate

    J'ai mis en commentaire la ligne
    <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
    dans le persistence.xml, je ne sais pas pourquoi tu précises cet attribut mais dans un contexte JTA, c'est le conteneur qui est maître de la transaction.

    J'ai vidé ta table employee, recalé la valeur dans PKEYS à 1 pour EMPLOYEE et le résultat de l'exécution de ta servlet est tout à fait correct :

    Nom : Capture.PNG
Affichages : 49
Taille : 8,8 Ko

    (j'aurais dû recalé à 0 plutôt que 1 mais bon, ce n'est pas très important, on voit bien que ça se suit)

    Donc, soit c'est la version 4.3 d'Hibernate qui a un bug, soit c'est ton projet qui fait quelque chose de différent...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    décembre 2004
    Messages
    164
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : décembre 2004
    Messages : 164
    Points : 64
    Points
    64
    Par défaut
    Bonjour,
    Bon cela s'est un peu bousculé ces derniers temps, mais j'essaye quand même de comprendre même si de toutes façons les choix ont été faits d'aller sur EclipseLink, mais je voulais comprendre.
    Pour répondre à ta question sur l'architecture, à l'origine c'est bien un EAR avec EJB module de Web module, mais j'ai simplifié l'exemple en embarquant le tout dans une Web Application.
    Je suis sous Glassfish et si j'enlève la ligne :
    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
    Ça plante dès la première lecture.
    Voir : https://jmdoudoux.developpez.com/cou....php#hibernate Au chapitre 56.12.4.4. La stratégie transactional
    Du coup j'ai installé WildFly et j'ai recréer l'application ex nihilo, le fichier persitence.xml étant le suivant :
    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
      <persistence-unit name="EmployeesJPA-ejbPU" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/datasources/Employees</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
          <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
          <property name="hibernate.show_sql" value="true"/>
        </properties>
      </persistence-unit>
    </persistence>

    Et là miracle (avec quelques soucis au passage pour le DataSource MySql) tout fonctionne parfaitement, on part de 14 pour passer à 18 aussi bien dans pkeys que dans employee.
    J'a surtout noté qu'il ne m'a pas été nécessaire de référencer la bibliothèque Hibernate 4.3 car WildFly embarque Hibernate tout comme Glassfish embarque EclipseLink (sur-ensemble de TopLink), en gros il faut prendre l'ORM de son serveur d'applications, point final !
    Voilà et merci encore de t'être intéressé à mon problème.

  10. #10
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    novembre 2006
    Messages
    7 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 7 183
    Points : 9 306
    Points
    9 306
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par clem_alain Voir le message
    J'a surtout noté qu'il ne m'a pas été nécessaire de référencer la bibliothèque Hibernate 4.3 car WildFly embarque Hibernate tout comme Glassfish embarque EclipseLink (sur-ensemble de TopLink), en gros il faut prendre l'ORM de son serveur d'applications, point final !
    C'est sûr, c'est mieux d'utiliser l'implémentation du serveur d'application, il y a plein de dépendances à mettre en place qui peuvent poser problème avec des versions d'autres api du serveur etc...
    En plus, JPA a été fait pour ça, on utilise l'api, l'implémentation, c'est autre chose... mais ça implique de ne pas utiliser des annotations spécifiques.

    Citation Envoyé par clem_alain Voir le message
    Voilà et merci encore de t'être intéressé à mon problème.
    je t'en prie
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. Pourquoi Hibernate et non pas JPA
    Par clubist dans le forum Hibernate
    Réponses: 5
    Dernier message: 15/12/2010, 14h58
  2. Réponses: 0
    Dernier message: 25/08/2009, 15h32
  3. [JPA / Hibernate] Cascade qui ne cascade pas !
    Par dazz_x dans le forum Persistance des données
    Réponses: 1
    Dernier message: 11/09/2007, 13h35
  4. Réponses: 3
    Dernier message: 01/06/2006, 16h26

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