my application loads list of entities should processed. happens in class uses scheduler
@component class taskscheduler { @autowired private taskrepository taskrepository; @autowired private handlingservice handlingservice; @scheduled(fixedrate = 15000) @transactional public void triggertransactionstatuschangehandling() { taskrepository.findbystatus(status.open).stream() .foreach(handlingservice::handle); } }
in handlingservice
processes each task in issolation using requires_new
propagation level.
@component class handlingservice { @transactional(propagation = propagation.requires_new) public void handle(task task) { try { processtask(task); // here actual processing take place task.setstatus(status.proccesed); } catch (runtimeexception e) { task.setstatus(status.error); } } }
the code works because started parent transaction on taskscheduler
class. if remove @transactional
annotation entities not managed anymore , update task entity not propagated db.i don't find natural make scheduled method transactional.
from see have 2 options:
1. keep code today.
- maybe it`s me , correct aproach.
- this varianthas least trips database.
2. remove @transactional
annotation scheduler, pass id of task , reload task entity in handlingservice.
@component class handlingservice { @autowired private taskrepository taskrepository; @transactional(propagation = propagation.requires_new) public void handle(long taskid) { task task = taskrepository.findone(taskid); try { processtask(task); // here actual processing take place task.setstatus(status.proccesed); } catch (runtimeexception e) { task.setstatus(status.error); } } }
- has more trips database (one query/element)
- can executed using
@async
can please offer opinion on correct way of tackling kind of problems, maybe method didn't know about?
if intention process each task in separate transaction, first approach not work because committed @ end of scheduler transaction.
the reason in nested transactions task
instances detached entities (session
s started in nested transactions not aware of instances). @ end of scheduler transaction hibernate performs dirty check on managed instances , synchronizes changes database.
this approach risky, because there may troubles if try access uninitialized proxy on task
instance in nested transaction. , there may troubles if change task
object graph in nested transaction adding other entity instance loaded in nested transaction (because instance detached when control returns scheduler transaction).
on other hand, second approach correct , straightforward , helps avoid of above pitfalls. only, read ids , commit transaction (there no need keep suspended while tasks being processed). easiest way achieve remove transactional
annotation scheduler , make repository method transactional (if isn't transactional already).
if (and if) performance of second approach issue, mentioned go asynchronous processing or parallelize processing degree. also, may want take @ extended sessions (conversations), maybe find suitable use case.
Comments
Post a Comment