Comment faire pour démarrer manuellement une transaction sur un partagées EntityManager au Printemps?
J'ai un LocalContainerEntityManagerFactoryBean
comme EntityManager
instance.
Pour rapidement tomber plein de tables", le contenu, je veux exécuter le code suivant:
@Service
public class DatabaseService {
@Autowired
private EntityManager em;
@Transactional
public void clear() {
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
}
}
Résultat:
ERROR org.springframework.integration.handler.LoggingHandler: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Si je fais cette modification:
public void clear() {
em.getTransaction().begin();
em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
}
Résultat:
ERROR org.springframework.integration.handler.LoggingHandler: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:245)
at com.sun.proxy.$Proxy84.getTransaction(Unknown Source)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
J'ai aussi essayé spring-data-jpa, mais échoue également:
public interface MyRepository extends CrudRepository<MyEntity, Integer> {
@Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true)
@Modifying
public void clear();
}
Alors, comment puis-je créer une transaction et d'exécuter le tronquer en commun de printemps contexte?
Le Printemps application est démarrée à l'aide de:
SpringApplication.run(AppConfig.class, args);
avoir:
@Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager(emf);
}
Veuillez poster le plein stacktraces y compris la cause.
N'utilisez pas de
Vous ne devriez pas commencer une transaction de vous-même... Le
J'ai essayé les deux le
N'utilisez pas de
@Autowired
utilisation @PersistenceContext
à la place.@PersistenceContext
n'a pas changer quoi que ce soit. Stacktrace mise à jour ci-dessus.Vous ne devriez pas commencer une transaction de vous-même... Le
@Transactional
devrait commencer... Avez-vous essayé réellement qu'après le changement?J'ai essayé les deux le
@Transactional
et la em.getTransaction().begin();
explicite, à la fois conduire chacun à les mêmes erreurs que ci-dessus.OriginalL'auteur membersound | 2014-10-28
Vous devez vous connecter pour publier un commentaire.
Vous devez utiliser
TransactionTemplate
objet de gérer les transactions impérativement:Pour créer TransactionTemplate suffit d'utiliser injecté
PlatformTransactionManager
:Et si vous souhaitez utiliser la nouvelle transaction, il suffit d'invoquer
OriginalL'auteur Jakub Kubrynski
Comme une solution de contournement j'ai maintenant créé un nouveau
EntityManager
explicite à l'aide de laEMF
, et le démarrage de l'opération manuellement.Ce n'est probablement pas l'idéal, mais fonctionne pour le moment.
@Transactional
ne devrait pas fonctionner, il doit y avoir quelque chose de mal avec votre configuration. Aussi ces deux solutions sont des solutions de contournement au lieu de réellement résoudre le problème. Une chose que je me demande est-avez-vous utilisé le bon@Transactional
celui de printemps et pas de la plus récente à partir de JEE7?J'utilise javax un
Et est l'API dans votre classpath ou seulement comme une condition de dépendance? Aussi, vous n'êtes pas en utilisant des interfaces, donc assurez-vous d'activer la classbased proxies... Enfin, pourriez-vous ajouter la pleine stacktrace à votre poste?
Au lieu de la
javax.transaction.Transactional
essayez d'utiliser le Printemps@Transactional
. Selon les classes disponibles la lajavax.transaction.Transactional
est activé ou désactivé."travaille pour le moment" le plus utilisé phrase en génie logiciel
OriginalL'auteur membersound
Spring Data JPA s'exécute automatiquement CRUD méthode dans les transactions (pour vous, sans avoir à régler quoi que ce soit à l'exception d'un gestionnaire de transactions). Si vous souhaitez utiliser des transactions pour vos méthodes de requête, vous pouvez simplement ajouter
@Transactional
:Sur un plan plus général, ce que vous avez déclaré ici est logiquement équivalent à
CrudRepository.deleteAll()
, sauf qu'il (votre déclaration) ne respecte pas, JPA niveau des cascades. Donc je me demandais c'est vraiment ce que vous avez l'intention de le faire. Si vous êtes à l'aide de Spring Boot, l'activation et l'opération d'installation du gestionnaire doit être pris en charge pour vous.Si vous souhaitez utiliser
@Transactional
sur le niveau de service, vous avez besoin de configurer à la fois unJpaTransactionManager
et activer annotation basée sur la gestion des transactions, soit par<tx:annotation-driven />
ou@EnableTransactionManagement
(qui ressemble à l'activation était la pièce manquante de votre tentative de créer des opérations sur la couche de service).Je soupçonne que la clé a été <tx:annotation-driven/> ne pas être mis en place au Printemps. Fondamentalement, le Printemps est la gestion de l'entité gestionnaire pour vous (afin de ne pas vous permettre de gérer vos propres opérations), mais vous ne dites pas comment gérer les transactions.
OriginalL'auteur Oliver Drotbohm
@Transactional
annotation ne doit pas être appliqué sur Dao méthode, mais sur une méthode de service. Bien que votre code ditDatabaseService
est un service, mais en insérantEntityManger
à l'intérieur d'un service n'a pas de sens.Bonne façon de mettre en œuvre est de créer un Dao comme ci-dessous.
Puis appeler la méthode dao à partir d'une méthode de service avec
@Transactional
annotation.Également, ajouter
@EnableTransactionManagement
dans votreConfiguration
classeOriginalL'auteur Manish Bansal