Java Spring启动事务无法在计时器中工作
我有一个如下的交易Java Spring启动事务无法在计时器中工作,java,spring,spring-boot,Java,Spring,Spring Boot,我有一个如下的交易 @Transactional public void changeJobStatus(Long jobId){ JobEntity jobEntity = jobRepository.findOneForUpdate(jobId); ... } TimerTask task = new TimerTask() { @Override public void run() { changeJobSt
@Transactional
public void changeJobStatus(Long jobId){
JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
...
}
TimerTask task = new TimerTask() {
@Override
public void run() {
changeJobStatus(jobId);
}
};
timer.schedule(task, waitTime);
@Service
public class SimpleTransactionService {
private final TransactionTemplate transactionTemplate;
@Autowired
public SimpleTransactionService(PlatformTransactionManager transactionManager){
transactionTemplate = new TransactionTemplate(transactionManager);
}
public void executeTransaction(ITransactionService task){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
task.transactionExecute();
}
});
}
}
findOneForUpdate是用悲观锁查找数据库
public interface JobRepository extends CrudRepository<JobEntity, Long>{
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select j from JobEntity j where j.id = :id")
JobEntity findOneForUpdate(@Param("id") Long id);
}
会有一个例外:
javax.persistence.TransactionRequiredException: no transaction is in progress
为什么会发生这种情况?如果有办法在TimerTask中调用transaction?对
changeJobStatus()
的调用有效地直接指向您的bean(自调用),因此在bean之间调用时不受通常的Spring代理的约束。因此,没有开始任何事务
请参阅:搜索“自我调用”
有几种可能的方法来实现这一点:
我的方法将取决于这是孤立的还是常见的情况。如果常见,我会研究“aspectj”模式;但我可能希望它是一个异常值,我可以坚持使用标准的Spring“代理”模式。这是由Spring的AOP限制造成的。正如Thomas所建议的,手动控制事务可以解决这个问题,而不是使用@Transactional。下面是详细的实现 我创建了一个简单的事务服务,如下所示
@Transactional
public void changeJobStatus(Long jobId){
JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
...
}
TimerTask task = new TimerTask() {
@Override
public void run() {
changeJobStatus(jobId);
}
};
timer.schedule(task, waitTime);
@Service
public class SimpleTransactionService {
private final TransactionTemplate transactionTemplate;
@Autowired
public SimpleTransactionService(PlatformTransactionManager transactionManager){
transactionTemplate = new TransactionTemplate(transactionManager);
}
public void executeTransaction(ITransactionService task){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
task.transactionExecute();
}
});
}
}
ITransactionService只是一个简单的接口,只有一种方法
public interface ITransactionService {
void transactionExecute();
}
下面是我在TimerTask中如何使用上面的内容
public void addTimerTask(Object param, Long waitTime){
TimerTask task = new TimerTask() {
@Override
public void run() {
simpleTransactionService.executeTransaction(() -> someOperation(param));
}
};
timer.schedule(task, waitTime);
}
someOperation是实际执行的事务。使用simple transaction service和lambda,无需任何注释即可完成事务。尝试了此注释@EnableTransactionManagement(mode=AdviceMode.ASPECTJ),但仍然不起作用。手动控制事务有效,谢谢!我在下面发布了一个实现。