I have a question about Spring 3.2.3 @Transactional annotation. My Service class looks like this:
@Service @Transactional
class InventoryDisclosureBO {
@Autowired InventoryDisclosureDAO inventoryDisclosureDAO;
private static final Logger log = LoggerFactory.getLogger( InventoryDisclosureBO.class);
public void processDisclosureData(InventoryDisclosureStatus data){
validate(data);
persist(data);
}
@Transactional(propagation = REQUIRES_NEW)
void persist(InventoryDisclosureStatus data) {
inventoryDisclosureDAO.setAllInvalid( data.getUnit());
inventoryDisclosureDAO.insert( data );
}
void validate(InventoryDisclosureStatus data) {
...
}
}
All works perfectly if I call persist() method. But if I comment out @Transactional at class level - transaction does not start. Could anybody tell me why Spring could ignore @Transactional on methol-level only?
You cannot call persist() from processDisclosureData() because it belongs to the same class and it will bypass transactional proxy created by Spring for InventoryDisclosureBO. You should call it from other beans to make @Transactional annotations work. When Spring injects a reference to InventoryDisclosureBO bean to other beans it actually injects a reference to InventoryDisclosureBOProxy which contains transactional logic, eg
class Bean2 {
@Autowire
private InventoryDisclosureBO idbo; <-- Spring will inject a proxy here
public void persist(InventoryDisclosureStatus data) {
idbo.persist(data); <-- now it will work via proxy
}
...
This is related to how spring generates the transactional proxies.
In the case where you have @Transactional at the class level, when you call InventoryDisclosureBO.processDisclosureData()
, in fact, you're calling a Spring proxy that starts the transaction, and then calls the real implementation.
If you only have @Transaction in persis(), spring doesn't start a transaction when you call InventoryDisclosureBO.processDisclosureData()
, and then it cannot detect that you've called InventoryDisclosureBO.persist()
So Spring basically ignores the annotation on persist
, because it cannot add the transactional proxy.
As a rule of thumb, the @Transactional annotation should be on a public method, and hopefully quite high in the call hierarchy (otherwise each persist would end up creating a new transaction)
You might find more information on this other SO question: Method Interceptor on private methods (any non-public methods behave in the same way)
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