java - Should I pass a managed entity to a method that requires a new transaction? -


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 (sessions 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