Spring: no hay EntityManager con una transacción real disponible para el hilo actual; no se puede procesar de manera confiable la llamada 'persistir'

Resuelto Michał Bil asked hace 9 años • 26 respuestas

Recibo este error cuando intento invocar el método "persistir" para guardar el modelo de entidad en la base de datos en mi aplicación web Spring MVC. Realmente no puedo encontrar ninguna publicación o página en Internet que pueda relacionarse con este error en particular. Parece que algo anda mal con el bean EntityManagerFactory, pero soy bastante nuevo en la programación Spring, así que me parece que todo está inicializado bien y de acuerdo con varios artículos tutoriales en la web.

despachador-servlet.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:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
 http://www.springframework.org/schema/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
 http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
 http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.0.xsd
  http://www.springframework.org/schema/jdbc
  http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
  http://www.springframework.org/schema/data/jpa
  http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
  http://www.springframework.org/schema/data/repository
  http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">

    <context:component-scan base-package="wymysl.Controllers" />
    <jpa:repositories base-package="wymysl.repositories"/> 
    <context:component-scan base-package="wymysl.beans" /> 
    <context:component-scan base-package="wymysl.Validators" /> 
    <bean
     class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
     <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

     <bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>

     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
        <property name="username" value="system" />
        <property name="password" value="polskabieda1" />
    </bean>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
    <property name="dataSource" ref="dataSource" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
            <property name="showSql" value="true" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">10</prop>
        </props>
    </property>
</bean>

    <mvc:annotation-driven />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
</bean>

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


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:resources mapping="/resources/*" location="/resources/css/"  
    cache-period="31556926"/>



</beans>

RegistroController.java

@Controller
public class RegisterController {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    PasswordValidator passwordValidator;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.setValidator(passwordValidator);
    }

    @RequestMapping(value = "/addUser", method = RequestMethod.GET)
    public String register(Person person) {


        return "register";

    }

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String register(@ModelAttribute("person") @Valid @Validated Person person, BindingResult result) {
        if(result.hasErrors()) {
            return "register";
        } else {
            entityManager.persist(person);
            return "index";

        }




    }
Michał Bil avatar Aug 28 '15 17:08 Michał Bil
Aceptado

Tuve el mismo problema y anoté el método @Transactionaly funcionó.

ACTUALIZACIÓN: al verificar la documentación de Spring, parece que, de forma predeterminada, PersistenceContext es de tipo Transacción, por eso el método tiene que ser transaccional ( http://docs.spring.io/spring/docs/current/spring-framework-reference/ html/orm.html ):

La anotación @PersistenceContext tiene un tipo de atributo opcional, cuyo valor predeterminado es PersistenceContextType.TRANSACTION. Este valor predeterminado es lo que necesita para recibir un proxy EntityManager compartido. La alternativa, PersistenceContextType.EXTENDED, es un asunto completamente diferente: esto da como resultado el llamado EntityManager extendido, que no es seguro para subprocesos y, por lo tanto, no debe usarse en un componente al que se accede simultáneamente, como un bean singleton administrado por Spring. Se supone que los EntityManager extendidos solo deben usarse en componentes con estado que, por ejemplo, residen en una sesión, con el ciclo de vida del EntityManager no vinculado a una transacción actual sino que depende completamente de la aplicación.

mlg avatar Sep 13 '2015 17:09 mlg

Obtuve esta excepción al intentar utilizar un método personalizado deleteBy en el repositorio de datos de Spring. La operación se intentó desde una clase de prueba JUnit.

La excepción no ocurre al usar la @Transactionalanotación en el nivel de clase JUnit.

Kishore Guruswamy avatar May 27 '2016 20:05 Kishore Guruswamy

Este error me tuvo confundido por tres días, la situación que enfrenté produjo el mismo error. Siguiendo todos los consejos que pude encontrar, jugué con la configuración pero fue en vano.

Finalmente lo encontré, la diferencia, el Servicio que estaba ejecutando estaba contenido en un frasco común, el problema resultó ser que AspectJ no trataba la instanciación del Servicio de la misma manera. De hecho, el proxy simplemente llamaba al método subyacente sin que se ejecutara toda la magia normal de Spring antes de la llamada al método.

Al final, la anotación @Scope colocada en el servicio según el ejemplo resolvió el problema:

@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
@Transactional
public class CoreServiceImpl implements CoreService {
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
        CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
        criteriaDelete.from(clazz);
        return entityManager.createQuery(criteriaDelete).executeUpdate();
    }

}

El método que publiqué es un método de eliminación, pero las anotaciones afectan a todos los métodos de persistencia de la misma manera.

Espero que esta publicación ayude a alguien que haya tenido el mismo problema al cargar un servicio desde un jar.

Chris March avatar Feb 07 '2016 07:02 Chris March