web-dev-qa-db-fra.com

Aucun EntityManager avec transaction réelle disponible pour le thread actuel - impossible de traiter de manière fiable l'appel 'persistant'

Aucun EntityManager avec transaction réelle disponible pour le thread actuel - impossible de traiter de manière fiable l'appel 'persistant'

quand je fais un test avec JUnit, la méthode persist fonctionne et je vois que mon objet est inséré, mais lorsque j'appelle la méthode via mon contrôleur, cela ne fonctionne pas

voici mon projet:

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">



<!--    <bean id="notification" class="com.app.sqli.notification.NotificationTask" /> -->

<!--    <task:scheduled-tasks> -->
<!--        <task:scheduled ref="notification" method="notifier" cron="*/2 * * * * *"/> -->
<!--    </task:scheduled-tasks> -->

<context:component-scan base-package="com.app.sqli" />  

    <mvc:annotation-driven />
    <bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource" />
       <property name="packagesToScan" value="com.app.sqli.entities" />
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
         </props>
      </property>
   </bean>


   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver" />
      <property name="url" value="jdbc:mysql://localhost:3306/sqli" />
      <property name="username" value="root" />
      <property name="password" value="" />
   </bean>


    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      <property name="entityManagerFactory" ref="entityManagerFactoryBean" />
   </bean>


   <tx:annotation-driven />


</beans>

ma classe de modèle: 

package com.app.sqli.models;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Collaborateur {

    @Id
    private int id;
    private String nom;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

}

ma classe DAO

package com.app.sqli.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;

import com.app.sqli.models.Collaborateur;

@Repository
public class CollaborateurDao implements IcollaborateurDao{

    @PersistenceContext
    private EntityManager em;

    @Override
    public void addCollaborateur(Collaborateur c) {
    em.persist(c);

    }

}

Ma classe de service

package com.app.sqli.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.app.sqli.dao.IcollaborateurDao;
import com.app.sqli.models.Collaborateur;

@Service
@Transactional
public class CollaborateurService implements IcollaborateurService{

    @Autowired
    private IcollaborateurDao cdao;

    @Override
    public void addCollaborateur(Collaborateur c) {
        cdao.addCollaborateur(c);

    }


}

Et mon contrôleur 

package com.app.sqli.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.app.sqli.models.Collaborateur;
import com.app.sqli.services.IcollaborateurService;

@org.springframework.stereotype.Controller
public class Controller {
    @Autowired
    private IcollaborateurService cserv;

    @RequestMapping(value = "/index")
    public String index(Model m) {
        System.out.println("insertion ...");
        Collaborateur c = new Collaborateur();
        c.setId(11);
        c.setNom("nom");
        cserv.addCollaborateur(c);
        return "index";
    }

}
5
Mohamed Nabli

merci @mechkov pour votre temps et votre aide, Mon problème est résolu en modifiant mon fichier de configuration. J'ai donc utilisé une classe de configuration avec des annotations et son fonctionnement est parfait, je ne sais toujours pas où était le problème. 

    @Configuration
    @ComponentScan(basePackages = "your package")
    @EnableTransactionManagement
    public class DatabaseConfig {

        protected static final String PROPERTY_NAME_DATABASE_DRIVER = "com.mysql.jdbc.Driver";
        protected static final String PROPERTY_NAME_DATABASE_PASSWORD = "password";
        protected static final String PROPERTY_NAME_DATABASE_URL = "jdbc:mysql://localhost:3306/databasename";
        protected static final String PROPERTY_NAME_DATABASE_USERNAME = "login";

        private static final String PROPERTY_PACKAGES_TO_SCAN = "where your models are";
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource);
            entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
            entityManagerFactoryBean.setPackagesToScan(PROPERTY_PACKAGES_TO_SCAN);
            return entityManagerFactoryBean;
        }

        @Bean
        public BasicDataSource dataSource(){
            BasicDataSource ds = new BasicDataSource();
            ds.setDriverClassName(PROPERTY_NAME_DATABASE_DRIVER);
            ds.setUrl(PROPERTY_NAME_DATABASE_URL);
            ds.setUsername(PROPERTY_NAME_DATABASE_USERNAME);
            ds.setPassword(PROPERTY_NAME_DATABASE_PASSWORD);
            ds.setInitialSize(5);
            return ds;
        }

        @Bean
        public JpaVendorAdapter jpaVendorAdapter(){
            HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
            adapter.setDatabase(Database.MYSQL);
            adapter.setShowSql(true);
            adapter.setGenerateDdl(true);

//I'm using MySQL5InnoDBDialect to make my tables support foreign keys
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
            return adapter;
        }

        @Bean
        public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
            return new JpaTransactionManager(entityManagerFactory);
        }


    }
6
Mohamed Nabli

Je ne sais pas si quelqu'un qui lit ceci (aujourd'hui) a le même cas que le mien, mais j'ai eu le même problème. Heureusement, je pourrais y remédier simplement en mettant ce qui suit dans le fichier spring-conf.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:tx="http://www.springframework.org/schema/tx"
...
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

<bean id="tManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>

<!-- This does the trick! -->
<tx:annotation-driven transaction-manager="tManager" />

Remarque: J'utilise des transactions déclaratives par le biais d'annotations. Donc, si vous le faites, annoter votre méthode avec @Transactional peut également résoudre votre problème.

REFERENCE:

  1. http://blog.jhades.org/how-does-spring-transactional-really-work/
  2. http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/transaction.html
3
Loa

Juste pour confirmer, l'ajout de la dernière définition de bean résout ce problème!

Ma classe de configuration est comme ci-dessous:

@Configuration
@EnableTransactionManagement
@ComponentScan
public class OFSConfig {

    @Bean
    public IDAO<FuelStation> getFSService() {
        return new FSService();
    }

    @Bean
    public LocalEntityManagerFactoryBean emfBean() {
        LocalEntityManagerFactoryBean e = new LocalEntityManagerFactoryBean();
        e.setPersistenceUnitName("org.superbapps.db_OWSDB_PU");

        return e;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory em) {
        return new JpaTransactionManager(em);
    }
}

Le service lui-même est le suivant:

@Transactional
@Repository
public class FSService implements IDAO<FuelStation> {

    @PersistenceContext
    private EntityManager EM;

    public EntityManager getEM() {
        return EM;
    }

    public void setEM(EntityManager EM) {
        this.EM = EM;
    }

    @Override
    public List<FuelStation> getAll() {
        return EM.createNamedQuery("FuelStation.findAll")
                .getResultList();
    }

    @Override
    public FuelStation getByID(String ID) {
        FuelStation fs = (FuelStation) EM.createNamedQuery("FuelStation.findById")
                .setParameter("id", ID)
                .getSingleResult();

        return fs;
    }

    @Override
    public void update(FuelStation entity) {
        EM.merge(entity);
    }

}
1
dobrivoje