L'appel de @les méthodes Transactionnelles à partir d'un autre thread (Runnable)
Est-il une solution simple pour sauvegarder les données dans la base de données à l'aide de JPA dans un nouveau thread?
Mon Printemps en fonction de l'application web permet à l'utilisateur de gérer les tâches planifiées. De l'exécution, il peut créer et démarrer de nouvelles instances de tâches prédéfinies. Je suis à l'aide du printemps TaskScheduler et tout fonctionne bien.
Mais j'ai besoin d'enregistrer le résultat booléen de tous les licenciés de la tâche dans la base de données. Comment puis-je faire cela?
EDIT:
J'ai de généraliser ma question: j'ai besoin d'appeler une méthode sur mon @classe de Service de tâches. Parce que le résultat de la tâche doit être "traitées" avant de l'enregistrer dans la base de données.
EDIT 2:
Version simplifiée de mon code problématique vient ici. Lorsque saveTaskResult() est appelée à partir du planificateur, le message est imprimé, mais rien n'est enregistré dans la base de données. Mais chaque fois que j'appelle saveTaskResult() du contrôleur, l'enregistrement est correctement enregistré dans la base de données.
@Service
public class DemoService {
@Autowired
private TaskResultDao taskResultDao;
@Autowired
private TaskScheduler scheduler;
public void scheduleNewTask() {
scheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
//do some action here
saveTaskResult(new TaskResult("result"));
}
}, 1000L);
}
@Transactional
public void saveTaskResult(TaskResult result) {
System.out.println("saving task result");
taskResultDao.persist(result);
}
}
- Quel est le problème exactement? Vous démarrez un thread, vous appelez votre Ressort des services exactement comme vous l'auriez fait si vous n'aviez pas commencé un fil, et tout devrait être OK.
- Le problème est la cible d'affaires de la méthode est @Transactionnelle. Lorsque j'appelle cette méthode run(), les données obtenez pas persisté. (J'ai mis à jour la question du titre)
- Le transactionnel de l'intercepteur ne se soucie pas si le thread appelant la méthode est un thread créé par votre conteneur de servlet, ou d'un fil créé par vous. Il devrait fonctionner. Nous montrer un peu de code.
- Exemple de code ajouté dans la question d'origine
- Ce qui Ressort du gestionnaire de transactions utilisez-vous?
- org.springframework.orm.jpa.JpaTransactionManager
Vous devez vous connecter pour publier un commentaire.
Le problème avec ton code, c'est que vous vous attendez à une transaction doit être entrepris lorsque vous appelez
saveTaskResult()
. Cela ne se produira pas parce que le Printemps utilise AOP de démarrer et d'arrêter les opérations.Si vous obtenez une instance de la transaction de Printemps de la fève de haricot usine, ou par l'injection de dépendance, ce que vous obtenez est en fait un proxy autour de la fève. Ce proxy démarre une transaction avant l'appel de la méthode, et s'engage ou des restaurations de la transaction une fois que la méthode est terminée.
Dans ce cas, vous appelez une méthode local de la fève, sans passer par le transactionnel proxy. Mettre le
saveTaskResult()
(méthode annotée avec@Transactional
) dans un autre Printemps bean. Injecter ce Printemps d'autres fève dans DemoService, et d'appeler les autres ressorts de la fève de DemoService, et tout ira bien.Transactions sont organisées au fil de stockage local.
Si votre autre méthode est en cours d'exécution d'un thread avec
@Transactional
annotation.La valeur par défaut est
REQUIRED
ce qui signifie que si vous exécutez une méthode annotée avec@Transacitonal
à partir d'un thread différent, vous aurez une nouvelle transaction (comme il n'y a pas de transaction détenus dans le thread local storage de ce fil).