java - transaction - transacciones jpa
Spring: no hay EntityManager con una transacción real disponible para el subproceso actual: no se puede procesar de manera confiable la llamada ''persistente'' (12)
Este error me hizo perder el tiempo durante 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. En efecto, el proxy simplemente estaba llamando al método subyacente sin que se ejecutara toda la magia Spring normal 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 he publicado 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 ha tenido problemas con el mismo problema al cargar un servicio desde un jar
Recibo este error cuando intento invocar el método "persistente" 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 está mal con el bean EntityManagerFactory, pero soy bastante nuevo en la programación de Spring, así que para mí parece que todo está bien inicializado y de acuerdo con varios artículos de tutoriales en la web.
dispatcher-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>
RegisterController.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";
}
}
Esto nos ayudó, tal vez pueda ayudar a otros en el futuro.
@Transaction
no funcionaba para nosotros, pero esto sí:
@ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")
Obtuve esta excepción al intentar usar 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 anotación
@Transactional
en el nivel de clase JUnit.
Para nosotros, el problema se redujo a la misma configuración de contexto en múltiples archivos de configuración. Compruebe que no ha duplicado lo siguiente en varios archivos de configuración.
<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />
Quité el modo de
methodWithANumberOfDatabaseActions() {
methodA( ...)
methodA( ...)
}
@Transactional
void methodA( ...) {
... ERROR message
}
para hacer que esto funcione
Tuve el mismo código de error cuando utilicé
@Transaction
en un método / nivel de acción incorrecto.
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
Tuve que colocar el
@Transactional
justo encima del método
methodWithANumberOfDatabaseActions()
, por supuesto.
Eso resolvió el mensaje de error en mi caso.
Tuve el mismo error al acceder a un método anotado ya transaccionalmente desde un método no transaccional dentro del mismo componente:
Before:
@Component
public class MarketObserver {
@PersistenceContext(unitName = "maindb")
private EntityManager em;
@Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
@Async
public void startObserving() {
executeQuery(); //<-- Wrong
}
}
//In another bean:
marketObserver.startObserving();
Solucioné el error llamando a executeQuery () en el componente auto-referenciado:
Fixed version:
@Component
public class MarketObserver {
@PersistenceContext(unitName = "maindb")
private EntityManager em;
@Autowired
private GenericApplicationContext context;
@Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
@Async
public void startObserving() {
context.getBean(MarketObserver.class).executeQuery(); //<-- Works
}
}
Tuve el mismo error porque cambié de configuración XML a Java.
El punto era que no
<tx:annotation-driven/>
etiqueta
<tx:annotation-driven/>
, como sugirió Stone Feng.
Así que acabo de agregar
@EnableTransactionManagement
como se sugiere aquí
Configuración de transacciones controladas por anotaciones en primavera en @Configuration Class
, y funciona ahora
Tuve el mismo problema y
@Transactional
el método como
@Transactional
y funcionó.
ACTUALIZACIÓN: comprobando la documentación de primavera, parece que, por defecto, el 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, que por defecto 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 un 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 EntityManagers extendidos solo se usan 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.
Tuve el mismo problema y agregué
tx:annotation-driven
en
tx:annotation-driven
en
applicationContext.xml
y funcionó.
Tuve este problema durante días y nada de lo que encontré en línea me ayudó, estoy publicando mi respuesta aquí en caso de que ayude a alguien más.
En mi caso, estaba trabajando en un microservicio que se llamaba a través de la comunicación remota, y el proxy remoto no estaba recogiendo mi anotación @Transactional a nivel de servicio.
Agregar una clase de delegado entre las capas de servicio y dao y marcar el método de delegado como transaccional me arregló esto.
boardRepo.deleteByBoardId (id);
Enfrenté el mismo problema. GOT javax.persistence.TransactionRequiredException: no hay EntityManager con transacción real disponible para el hilo actual
Lo resolví agregando la anotación @Transactional sobre el controlador / servicio.