Running an aspect inside the transaction boundary of the calling method - spring

I am having a method annotated with spring #Transactional and another custom annotation #Counter. #counter is used by many other methods from different classes.
#Transactional
#Counter
public int myMethod() {
....
}
#Counter is intercepted by an aspect which does some count related logic and saves to DB and is marked with #Transactional, hence completes in different transaction than the myMethod().
when I call this myMethod(), first this aspect is called and after it completes then the transaction for myMethod() is created and then executes the business logic in myMethod().
Issue here is, if any exception thrown in myMethod(), it rolls back all the changes. But since #Counter is in different transaction, it still is processing and doing counter related updates and does not roll back the counter related changes.
My question is: is it possible to bring the aspect of #Counter also within the same trancaction boundary of myMethod()? Is it possible to create the transaction for myMethod() even before the #Counter is called?
Edit 1: I have tried using #Order (value 5) for the around aspect and for the myMethod() transactional order wil be inferred from context xml
<tx:annotation-driven transaction-manager="transactionManager" order = "1"/>
Still transaction gets created only after aspect completes
Edit 2:
#Aspect
public class CounterHandler {
#Autowired
private counterOperation CounterOperation;
#Around("#annotation(com.prime.monitor.counter.aspect.Counter)")
public Object aroundAdvice(final ProceedingJoinPoint methodInvocation) {
//counter related operation
return counterOperation.prepareCounter(methodInvocation);
}
}

Related

Without JPA #Transaction and save() when is the commit done?

When a method has a #Transaction annatotion, I know the commit is done at the end of the method. But when I don't use #Transaction, it's not clear to me when the commit is done. In my example I don't use #Transaction, do the real change in another service and don't use someRepository .save(), but it still works:
#Service
public class ServiceA {
private final SomeRepository someRepository;
private final ServiceB serviceB;
public ServiceA(SomeRepository someRepository, ) {
this.someRepository = someRepository;
this.serviceB = serviceB;
}
// Called from controller
public void doStuff() {
var someEntity = someRepository.findById(1);
serviceB.makeChange(someEntity);
}
}
#Service
public class ServiceB {
public ServiceB() {}
public void makeChange(SomeEntity someEntity) {
someEntity.setName("Test"); // this is working and committed to the database
}
}
So actually I have 2 questions:
When I don't add a #Transaction annatotion to a method when is the commit done?
I don't even have to call someRepository.save(entity)? I thought that worked only when using the #Transaction annotation?
Context:
Spring Boot 2.2.6
"spring-boot-starter-data-jpa" as dependency
first one clarification: the #Transactional annotation does not mean there is a commit at end of the method. It means the method joins the transaction (or start a new one - this depends on the propagation attributes to be precise), so the commit (or rollback) will be performed at the end of the transaction, which can (and often does) involve multiple methods with various DB access.
Normally Spring (or another transaction manager) takes care of this (ie disabling auto-commit).
#Transactional missing
There is no transactional context so the commit is performed immediately as the database in modified. There is no rollback option and, if there is an error, the data integrity might be violated,
#Transactional defined
During the transactions the JPA entities are in managed-state, at the end of the transaction the state is automatically flushed to the DB (no need to call someRepository.save(entity)

Grails/Spring REQUIRES_NEW rolling back outer transaction

REQUIRES_NEW is rolling back all transactions:
I have a method marked #Transactional(propagation = REQUIRES_NEW)
within a bean that also has methods marked #Transactional(propagation = REQUIRED). These methods never call each other. They are called from another bean individually. However when my method that has been marked with REQUIRES_NEW fails, it rolls back the whole transaction, including the methods that are marked REQUIRED (which is problematic).
My understanding is that if factored this way Spring AOP will have a chance to intercept the REQUIRES_NEW method and start a new logical transaction.
The general idea looks like this:
#Transactional
class TransactionalBean{
#Transactional(propagation = REQUIRED)
public void methodA(){ //do transactional work }
#Transactional(propagation = REQUIRES_NEW)
public void methodB(){ //do transactional work }
}
And then the calling bean looks like so:
#Transactional
class CallingBean{
#Autowired
TransactionalBean
public void doWork(){
TransactionalBean.methodA();
TransactionalBean.methodB();
}
}
So if method A and B succeed, everything is fine. However when method B fails work done in method A gets rolled back. My understanding is that when methodB() is invoked that it 'should' get intercepted by AOP and start a new transaction and suspend the other transaction, but it's not working. How do I fix this? I'm using Grails 2.5, Hibernate, JPA
The problem is with the way the CallingBean was marked as #Transactional. What is happening is that the CallingBean is creating a transaction, let's say t1. The CallingBean is invoking the two transactional methods methodA and methodB. Since methodA requires a transaction, it will make use of the existing transaction t1. However, methodB will create a new transaction as the annotation requires a new one, let's say t2. The transactional boundary of methodA does not end when the control exits methodA, but is kept alive until methodB is completed since the transaction started at the calling bean. Now that the transaction t2 is failing in methodB, the exception would bubble up to the calling bean and the transaction t1 would fail.
In order to resolve this, you can do one of the following based on your needs.
Turn off the #Transactional annotation in the CallingBean class.
//#Transactional
class CallingBean{
...
}
Update the annotation to use noRollbackFor option
#Transactional(noRollbackFor={WhateverException.class})
class CallingBean{
...
}

Testing #TransactionalEvents and #Rollback

I've been trying to test out #TransactionalEvents (a feature of Spring 4.2 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2) with our existing Spring JUnit Tests (run via either #TransactionalTestExecutionListener or subclassing AbstractTransactionalUnit4SpringContextTests but, it seems like there's a forced choice -- either run the test without a #Rollback annotation, or the events don't fire. Has anyone come across a good way to test #TransactionalEvents while being able to #Rollback tests?
Stéphane Nicoll is correct: if the TransactionPhase for your #TransactionalEventListener is set to AFTER_COMMIT, then having a transactional test with automatic rollback semantics doesn't make any sense because the event will never get fired.
In other words, there is no way to have an event fired after a transaction is committed if that transaction is never committed.
So if you really want the event to be fired, you have to let the transaction be committed (e.g., by annotating your test method with #Commit). To clean up after the commit, you should be able to use #Sql in isolated mode to execute cleanup scripts after the transaction has committed. For example, something like the following (untested code) might work for you:
#Transactional
#Commit
#Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD,
config = #SqlConfig(transactionMode = TransactionMode.ISOLATED))
#Test
public void test() { /* ... */ }
Regards,
Sam (author of the Spring TestContext Framework)
Marco's solution works but adding REQUIRES_NEW propagation into business code is not always acceptable. This modifies business process behavior.
So we should assume that we can change only test part.
Solutin 1
#TestComponent // can be used with spring boot
public class TestApplicationService {
#Autowired
public MyApplicationService service;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void doSomething() {
service.doSomething();
}
}
This wraps the real service into test component that can be decorated with REQUIRES_NEW propagation. This solution doesn't modify other logic than testing.
Solution 2
#Transactional
#Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD,
config = #SqlConfig(transactionMode = TransactionMode.ISOLATED))
#Test
public void test() {
MyApplicationService target = // ...
target.doSomething();
TestTransaction.flagForCommit(); //Spring-test since 4.1 - thx for Sam Brannen
TestTransaction.end();
// the event is now received by MyListener
// assertions on the side effects of MyListener
// ...
}
This is simplest solution. We can end test transaction and mark it for commit. This forces transactional events to be handled. If test changes data, cleanup sql script must be specified, otherwise we introduce side effects with committed modified data.
Sam Brannen's solution almost works with regard to adam's comment.
Actually the methods annotated with #TransactionalEventListener are called after the test method transaction is committed. This is so because the calling method, which raises the event, is executing within a logical transaction, not a physical one.
Instead, when the calling method is executed within a new physical transaction, then the methods annotated with #TransactionalEventListener are invoked at the right time, i.e., before the test method transaction is committed.
Also, we don't need #Commit on the test methods, since we actually don't care about these transactions. However, we do need the #Sql(...) statement as explained by Sam Brannen to undo the committed changes of the calling method.
See the small example below.
First the listener that is called when the transaction is committed (default behavior of #TransactionalEventListener):
#Component
public class MyListener {
#TransactionalEventListener
public void when(MyEvent event) {
...
}
}
Then the application service that publishes the event listened to by the above class. Notice that the transactions are configured to be new physical ones each time a method is invoked (see the Spring Framework doc for more details):
#Service
#Transactional(propagation = Propagation.REQUIRES_NEW)
public class MyApplicationService {
public void doSomething() {
// ...
// publishes an instance of MyEvent
// ...
}
}
Finally the test method as proposed by Sam Brannen but without the #Commitannotation which is not needed at this point:
#Transactional
#Sql(scripts = "/cleanup.sql", executionPhase = AFTER_TEST_METHOD,
config = #SqlConfig(transactionMode = TransactionMode.ISOLATED))
#Test
public void test() {
MyApplicationService target = // ...
target.doSomething();
// the event is now received by MyListener
// assertions on the side effects of MyListener
// ...
}
This way it works like a charm :-)

Spring - #Transactional with ScheduledExecutorService - What happens in background?

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)

#transactional in spring jpa not updating table

I am using spring jpa transactions in my project.One Case includes inserting a data in a synchronized method and when another thread accesses it the data is not updated.My code is given below :
public UpdatedDTO parentMethod(){
private UpdatedDTO updatedDTO = getSomeMethod();
childmethod1(inputVal);
return updatedDTO;
}
#Transactional
public synchronized childmethod1(inputVal){
//SomeCodes
//Place where update takes place
TableEntityObject obj = objectRepository.findByInputVal(inputVal);
if(obj == null){
childMethod2(inputVal);
}
}
#Transactional
public void childMethod2(inputVal){
//Code for inserting
TableEntityObject obj = new TableEntityObject();
obj.setName("SomeValue");
obj.setValueSet(inputVal);
objectRepository.save(obj);
}
Now if two threads access at the same time and if first thread completes childmethod2 and childmethod1 and without completing parentMethod() after that if second thread comes to the childMethod1() and checks if data exists,the data is null and is not updated by first thread.I have tried many ways like
#Transactional(propagation = Propagation.REQUIRES_NEW)
public synchronized childmethod1(inputVal){
//SomeCodes
//Place where update takes place
TableEntityObject obj = objectRepository.findByInputVal(inputVal);
if(obj == null){
childMethod2(inputVal);
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void childMethod2(inputVal){
//Code for inserting
TableEntityObject obj = new TableEntityObject();
obj.setName("SomeValue");
obj.setValueSet(inputVal);
objectRepository.save(obj);
}
also tried taking off #transactional in the childMethod1() but nothing works out.I know im doing something wrong here , but couldnt figure out where and what exactly i am doing wrong.Can anyone help me out with this
#Transactional is resolved using proxies on spring beans. It means it will have no effect if your method with #Transactional is called from the same class. Take a look at Spring #Transaction method call by the method within the same class, does not work?
The easiest would be moving those methods into separate service.
Typical checklist I follow in cases like these :
If Java based configuration then make sure
#EnableTransactionManagement annocation is present in the class
containing the #Configuration annotation
Make sure the transactionManager bean is created, again this should be mentioned in the configuration class.
Use of #Transactional annocatio over the method which is calling the repository, typically a class in the DAO layer
Adding the #Service annotation for the class which is invoking the methods in the repository
Nice blog which explains the Transaction configuration with JPA in depth --> http://www.baeldung.com/2011/12/26/transaction-configuration-with-jpa-and-spring-3-1/68954

Resources