I want to know what actually happens when you annotate a method with #Transactional with ScheduledExecutorService?
Assume that the methodA is called externally. Am I correct in assuming that when methodA is called, someDao.methodDao() joins in a transaction and scheduleMethodB() returns immediately.
Later after 2 seconds, the scheduler calls the methodB(). What would this hold in this case? Would it hold the TransactionProxy and execute methodB in a separate transaction? If not, then how would we able to achieve this.
I am aware that #Transactional is based on proxies so is methodB call a self invocation under scheduler.
Note: Since this mechanism is based on proxies, only 'external' method
calls coming in through the proxy will be intercepted. This means that
'self-invocation', i.e. a method within the target object calling some
other method of the target object, won't lead to an actual transaction
at runtime even if the invoked method is marked with #Transactional!
public class ServiceABImpl implements ServiceAB {
#Autowired
private ScheduledExecutorService scheduledExecutorService;
#Transactional
public void methodA() {
//do some work in a transaction.
someDao.methodDao();
//schedule a methodB
scheduleMethodB();
}
public void scheduleMethodB() {
scheduledExecutorService.schedule(() -> {
this.methodB();
return "";
},
2,
TimeUnit.SECONDS);
}
#Transactional
public void methodB() {
}
}
Since the class is not annotated with #Transactional, the decision of whether an invoked method participates in the transaction of the parent invokee method depends on whether you annotate the invoked methods also with #Transactional and what propagation level you configure it with I think. So for example
#Transactional(propagation=Propagation.REQUIRED)
Related
AFAIK
In proxy mode (which is the default), only 'external' method calls
coming in through the proxy will be intercepted. This means that
'self-invocation', i.e. a method within the target object calling some
other method of the target object, won't lead to an actual transaction
at runtime even if the invoked method is marked with #Transactional!
But here is: Transactional.TxType.REQUIRES_NEW
Will be the second transaction created?
#Service
public class SomeService {
#Transactional
public void doSomeLogic() {
// some logic
doOtherThings();
// some logic
}
#Transactional(Transactional.TxType.REQUIRES_NEW)
private void doOtherThings() {
// some logic
}
To get an answer to this question, you need to know how a proxy works.
When you annotate a method inside a bean, the proxy will wrap that bean with the appropriate logic. This means that if you call that annotated method of your bean, the request will first be sent to the proxy object (named with $), which will then call the bean's method. If this method calls another method of the same bean, it will call it without invoking a proxy which has a logic, e.x., of transaction management.
Example: Here is the code which will be wrapped by proxy and an appropriate diagram of its work.
#Service
public class SomeService {
#Transactional
public void foo() {
// this next method invocation is a direct call on the 'this' reference
bar();
}
#Transactional(Transactional.TxType.REQUIRES_NEW)
public void bar() {
// some logic...
}
}
Source
Hence, the answer is No.
Hope that's a little bit more clear now.
In my Spring Boot project I have implemented following service method:
#Transactional
public boolean validateBoard(Board board) {
boolean result = false;
if (inProgress(board)) {
if (!canPlayWithCurrentBoard(board)) {
update(board, new Date(), Board.AFK);
throw new InvalidStateException(ErrorMessage.BOARD_TIMEOUT_REACHED);
}
if (!canSelectCards(board)) {
update(board, new Date(), Board.COMPLETED);
throw new InvalidStateException(ErrorMessage.ALL_BOARD_CARDS_ALREADY_SELECTED);
}
result = true;
}
return result;
}
Inside this method I use another service method which is called update:
#Transactional(propagation = Propagation.REQUIRES_NEW)
public Board update(Board board, Date finishedDate, Integer status) {
board.setStatus(status);
board.setFinishedDate(finishedDate);
return boardRepository.save(board);
}
I need to commit changes to database in update method independently of the owner transaction which is started in validateBoard method. Right now any changes is rolling back in case of any exception.
Even with #Transactional(propagation = Propagation.REQUIRES_NEW) it doesn't work.
How to correctly do this with Spring and allow nested transactions ?
This documentation covers your problem - https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#transaction-declarative-annotations
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. #PostConstruct.
However, there is an option to switch to AspectJ mode
Using "self" inject pattern you can resolve this issue.
sample code like below:
#Service #Transactional
public class YourService {
//... your member
#Autowired
private YourService self; //inject proxy as an instance member variable ;
#Transactional(propagation= Propagation.REQUIRES_NEW)
public void methodFoo() {
//...
}
public void methodBar() {
//call self.methodFoo() rather than this.methodFoo()
self.methodFoo();
}
}
The point is using "self" rather than "this".
The basic thumb rule in terms of nested Transactions is that they are completely dependent on the underlying database, i.e. support for Nested Transactions and their handling is database dependent and varies with it.
In some databases, changes made by the nested transaction are not seen by the 'host' transaction until the nested transaction is committed. This can be achieved using Transaction isolation in #Transactional (isolation = "")
You need to identify the place in your code from where an exception is thrown, i.e. from the parent method: "validateBoard" or from the child method: "update".
Your code snippet shows that you are explicitly throwing the exceptions.
YOU MUST KNOW::
In its default configuration, Spring Frameworkâs transaction
infrastructure code only marks a transaction for rollback in the case
of runtime, unchecked exceptions; that is when the thrown exception is
an instance or subclass of RuntimeException.
But #Transactional never rolls back a transaction for any checked exception.
Thus, Spring allows you to define
Exception for which transaction should be rollbacked
Exception for which transaction shouldn't be rollbacked
Try annotating your child method: update with #Transactional(no-rollback-for="ExceptionName") or your parent method.
Your transaction annotation in update method will not be regarded by Spring transaction infrastructure if called from some method of same class. For more understanding on how Spring transaction infrastructure works please refer to this.
Your problem is a method's call from another method inside the same proxy.It's self-invocation.
In your case, you can easily fix it without moving a method inside another service (why do you need to create another service just for moving some method from one service to another just for avoid self-invocation?), just to call the second method not directly from current class, but from spring container. In this case you call proxy second method with transaction not with self-invocatio.
This principle is useful for any proxy-object when you need self-invocation, not only a transactional proxy.
#Service
class SomeService ..... {
-->> #Autorired
-->> private ApplicationContext context;
-->> //or with implementing ApplicationContextAware
#Transactional(any propagation , it's not important in this case)
public boolean methodOne(SomeObject object) {
.......
-->> here you get a proxy from context and call a method from this proxy
-->>context.getBean(SomeService.class).
methodTwo(object);
......
}
#Transactional(any propagation , it's not important in this case)public boolean
methodTwo(SomeObject object) {
.......
}
}
when you do call context.getBean(SomeService.class).methodTwo(object); container returns proxy object and on this proxy you can call methodTwo(...) with transaction.
You could create a new service (CustomTransactionalService) that will run your code in a new transaction :
#Service
public class CustomTransactionalService {
#Transactional(propagation= Propagation.REQUIRES_NEW)
public <U> U runInNewTransaction(final Supplier<U> supplier) {
return supplier.get();
}
#Transactional(propagation= Propagation.REQUIRES_NEW)
public void runInNewTransaction(final Runnable runnable) {
runnable.run();
}
}
And then :
#Service
public class YourService {
#Autowired
private CustomTransactionalService customTransactionalService;
#Transactional
public boolean validateBoard(Board board) {
// ...
}
public Board update(Board board, Date finishedDate, Integer status) {
this.customTransactionalService.runInNewTransaction(() -> {
// ...
});
}
}
I am new with spring/grails transaction and i am still not clear after reading so i am posting it in here,
I have a service class which is annotated as #Transactional
and i have methods some of them are annotated as
#Transactional(propagation = Propagation.REQUIRES_NEW)
and some of them are not.
#Transactional
class SomeService {
def findJob() {
MyInstance myInstance = getMeAJob();
if (myInstance) {
doSomeThing(myInstance)
doTask()
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception)
private doSomeThing(MyInstance myInst) {
myObj = MyInstance.lock(myInst.id)
try {
differentObj = doTask(myObj)
myObj.save()
doAnotherThing()
}
} catch (Exception e) {
log("Error in doAnotherTask")
}
}
private doAnotherThing(MyInstace myInst) {
perform some update on myInst
myInstant.save(flush: true)
}
private doTask() {
}
Suppose , I have transaction t1 from the class level and t2
transaction from doSomething()- REQUIRES_NEW.
Method that will execute in t1 - findJob() and doTask()
Method that will execute in t2 - doSomeThing() - doesn't affect the
"t1" in case of exception (Rollback)
Which one will be for doAnotherThing() method? Since I am calling it from doSomething()?
When you have a class-scope annotation, any method that's not annotated uses those settings, and annotated methods override the class-level settings with the settings from that annotation.
Note however that when using Spring's annotation support (with the #org.springframework.transaction.annotation.Transactional) annotation only public methods are supported. There won't be an error, but the annotations are silently ignored.
But even if you make doSomeThing public (either implicitly by removing the private keyword or explicitly by changing it to public) it won't do what you expect when you call doSomeThing from findJob. This is because Spring's annotation triggers the creation of a proxy of your class at runtime. The Spring bean that's registered for your service in that case is a proxy instance that has a "real" instance of your class as its delegate. All transactional public methods are intercepted by the proxy, which starts/joins/etc. a transaction and then calls your service method. Once you're "underneath" the proxy in the service instance all method calls are direct and any annotation settings have no effect. To get it to work you would need to call the method on the Spring bean and go through the proxy to start a new transaction.
To avoid this proxy issue, use the Grails #grails.transaction.Transactional annotation instead. It supports the same transaction features as the Spring annotation, but instead of creating a proxy, an AST transformation rewrites your methods to wrap them within a transaction. This makes it possible to make direct method calls like you're doing and create a new transaction or run under other transaction semantics as defined by the annotation attributes.
I did a talk a while back on using transactions in Grails that might shed some light.
I have read the official documentation of Spring about the
#Transactional(Propagation.REQUIRED)
annotation but still have some doubts. I will show you an example about how I thinks it behaves:
First Service
public class MyServiceImpl implements MyService{
#AutoWired
private OtherService otherService;
#Transactional(Propagation.REQUIRED)
public void saveItem(Item item){.....}
#Transactional(Propagation.REQUIRED)
public void updateItem(Item item){....}
}
#Transactional(Propagation.REQUIRED)
public void deleteItem(Item item){
otherService.checkItem(item);
...........
}
}
Second Service
public class OtherServiceImpl implements OtherService {
#Transactional(Propagation.REQUIRED)
public void checkItem(Item item){.....}
}
Making calls to MyServiceImpl class from a Spring Controller:
If I make one call to saveItem(), a new physical and logical transaction will be created, right?
If I make two calls to this service from the controller, one to saveItem() and the next to updateItem(),Spring will create for each method two physical different transactions, right?
If I make a call to deleteItem(), only one physical transaction will be created because it will be opened a transaction when deleteItem is called but the inner call from this method to otherService.checkItem() will reuse the first physical transaction, right?
REQUIRED means that one transaction is needed for running the method, so if one is not already ongoing at the beggining of the method then a new one is created (REQUIRED is the default propagation mode):
1) not necessarilly, if this was called from a method that already had an ongoing transaction
2) depends if the controller is transactional. It should not be by convention, only the service layer should define the scope of the transactions. so in the usual case of a non transactional controller you would have two transactions.
3) depends if where the call was made a transaction was already ongoing. if so then both methods would join a new transaction, if not delete item would create a transaction and otherService keep using it.
I've the following case:
#Interceptors(MyInterceptClass.class)
public void ejbMethod1()
{
}
#Interceptors(MyInterceptClass.class)
public void ejbMethod2()
{
ejbMethod1();
}
Is calling ejbMethod2 causes TWO interceptor calls to be executed?
Thanks.
I'll assume you mean #Interceptors (plural) annotation which defines the interceptor class which will be invoked upon annotated method invocation. #Interceptor annotation (singular) is for annotating a class which is an interceptor.
If so, then short answer is: no.
The interceptor is executed by the container. If your method invocation will not go through the container, then it will not be intercepted.
Therefore the following call to ejbMethod1():
#Interceptors(MyInterceptClass.class)
public void ejbMethod2() {
ejbMethod1();
}
won't activate the MyInterceptClass as it's the local call (non-EJB one).
If you'd like to call the interceptor once again, you should use business interface, so something like:
// Somewhere in the class
#Resource
SessionContext ctx;
#Interceptors(MyInterceptClass.class)
public void ejbMethod2() {
// This is explicit call which will go through the EJB Container
ctx.getBusinessObject(YourEJBClass.class).ejbMethod1();
}
This will make the EJB-aware call and will hit the interceptor while invoking ejbMethod1().