I have a transaction like below,
@Transactional
public void changeJobStatus(Long jobId){
JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
...
}
And findOneForUpdate is to lookup database with pessimistic lock,
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);
}
This works well, if I call changeJobStatus normally.
But when calling in a TimerTask like below,
TimerTask task = new TimerTask() {
@Override
public void run() {
changeJobStatus(jobId);
}
};
timer.schedule(task, waitTime);
there would be an exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
Why this happens? And if there is a way to call transaction in a TimerTask?
The call to changeJobStatus()
is effectively direct to your bean (self-invocation), and therefore not subject to the usual Spring proxying when calling between beans. For this reason no transaction is getting started.
See: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations search for "self-invocation".
There may be several potential ways to approach this:
My approach would depend on whether this is isolated, or a common case. If common, I'd investigate "aspectj" mode; but I would probably hope that it were an outlier and I could stick to the standard Spring "proxy" mode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With