4

My Service Class.

@Service
@Transactional(value = "transactionManager", readOnly = true, propagation = Propagation.REQUIRED)
public class DeviceServiceImpl{

@Transactional(readOnly = false)
public void blockAllDevices(){

    createSmsDeviceBlock();

}


public void createSmsDeviceBlock(){

    addToLogTables();

    smsService.sendSms();
}


@Transactional(readOnly = false,propagation = Propagation.REQUIRES_NEW)
public void addToLogTables(){
         try {
          //save object with DAO methods...
        } catch (Exception e) {
          throw new ServiceException(ServiceException.PROCESSING_FAILED, e.getMessage(), e);
        }
}

}

From my controller , service method blockAllDevices() getting called. addToLogTables() method is marked as Propergation.REQUIRED_NEW, but the problem is with the addToLogTables() method new transaction not getting created and existing transaction is using.

The thing i want to do is, the transaction on addToLogTables() method should be commit before execute smsService.sendSms() method.

My problem here, if transaction failed to commit , on method addToLogTables() method, it should not execute smsService.sendSms() method.

Dinesh Appuhami
  • 710
  • 1
  • 11
  • 24

1 Answers1

11

That's not a Propagation.REQUIRES_NEW issue. It's an issue with how @Transactional proxying works.

When Spring proxies your bean that's annotated with @Transactional, it basically wraps it in a proxy object and delegates to it after opening the transaction. When the delegated call returns, the proxy either commits or rolls back the transaction.

For example, your bean is

@Autowired
private DeviceServiceImpl deviceService;

Spring is actually going to inject a wrapper proxy.

So when you do

deviceService.blockAllDevices();

you are invoking the method on the proxy which has the transactional behavior. However, in blockAllDevices(), you are doing

createSmsDeviceBlock();

which is actually

this.createSmsDeviceBlock();

where this is referring to the actual object, not the proxy, so there is no transactional behavior.

This is further explained in the documentation.

You'll have to rework your design.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I can understand this, but are there any alternatives to do this...? That is create new transaction within same.. – Dinesh Appuhami Jan 28 '14 at 15:01
  • You'll have to make the calls from outside or redactor so that the transactional methods are on some other bean that you inject into this one. – Sotirios Delimanolis Jan 28 '14 at 15:13
  • 1
    You can use AspectJ-based transaction management with load-time or compile-time weaving and spring-aspects, which allows you to have transactional self-calls, private transactional methods etc. Have a look at the Spring documentation for more info. – Jukka Jan 28 '14 at 20:19