#Transactional within PanacheEntity? - quarkus

Is this allowed in quarkus?
#Entity
public class User extends PanacheEntity {
// is #Transactional annotation allowed within an Entity
#Transactional
public static final updateName(String name){
...
}
}
Does quarkus allow the annotation #Transactional to be set within a static method (which is normally not bound to a context (CDI-Bean))..depending on PanacheEntity.

No, that is not allowed.
You will get javax.persistence.TransactionRequiredException: Transaction is not active, consider adding #Transactional to your method to automatically activate one.
You have to add the annotation #Transactional to the wrapping method of your resource.
The built-in method persist() does not have the annotation set, so even the quarkus default method wont work without a wrapped #Transactional.

Related

Spring Instantiate a component dynamically inside a method

I'm trying to instantiate a component inside a method, to be more precise inside a rest method. I need a new instance of the component every time the rest method is invoked
#Validated
#RestController
#RequestMapping("test")
public class Test {
#GetMapping
public String test() {
// Spring equivalent of
// TestComponent component = new TestComponent();
return component.uuid();
}
}
My component is defined like this
#Scope
#Component
#Transactional
public class TestComponent {
private EntityManager entityManager;
private UUID randomUUID;
#Autowired
public TestComponent(EntityManager entityManager) {
this.entityManager = entityManager;
this.randomUUID = UUID.randomUUID();
}
public String uuid() {
// entityManager transactional stuff
return randomUUID.toString();
}
}
I tried to use a factory method but the instance was not transactional, I tried to use ApplicationContext.getBean but the instance was a singleton. How can I instantiate my component dynamically whenever I need it?
I'm using Spring 3.0.0-RC1
You can use different scopes to define the life cycle and visibility of that bean in the context. The default scope is Singleton, which means only one instance is created.
In your particular case, I think that you should choose between:
Prototype - creates a new instance every time a request for that specific bean is made. It can be defined with #Scope("prototype") annotation.
Request - each HTTP request has its own instance, only valid in the context of a web-aware Spring ApplicationContext. It can be defined with #RequestScope annotation.
To find out more details about all supported scopes, check the documentation.

#Transactional has no effect on JpaRepository

I have a parent transaction at controller layer, but I want to start a new transaction when I call a repository, to achieve this I tried annotating Repository interface as below
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{ }
However this seems to not start a new transaction upon calls to EventRepo#save. Why?
Here is my service layer.
public interface IApplicationService {
void save(Event event);
}
#Service
public class ApplicationService implements IApplicationService {
#Autowired
private EventRepo eventRepo;
#Override
public void save(Event event) {
eventRepo.save(event);
}
}
It is in turn called from controller layer
#RequestMapping(value="/{indicator}", method=RequestMethod.POST)
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
#ResponseBody
public String processRequest(#PathVariable Integer indicator) {
Event event = new Event("Student1");
service.save(event);
if(indicator != 0) {
throw new RuntimeException();
}
return "Success";
}
However everything works perfectly if I annotate Service interface with #Transactional
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface IApplicationService {
void save(Event event);
}
When I say working what is mean is, if I run the below curl commands I will see 2 rows in h2 db for Event entity
curl -X POST http://localhost:8080/1
curl -X POST http://localhost:8080/0
I understand it is good to control transactions at Service layer then repository or controller layer, constructing situation this way makes it easy to demonstrate the problem.
Spring boot starter version is 2.5.6
below dependencie have versions managed by springboot starter
spring-boot-starter-data-jpa
spring-boot-starter-web
lombok
h2
Here is a thread that suggests it should be ok to annotate Repository layer although discourages it.
#Transactional on a JpaRepository
In this Spring article we can read the following:
Additionally, we can get rid of the #Transactional annotation for the method as the CRUD methods of the Spring Data JPA repository implementation are already annotated with #Transactional.
To me, this means that whatever #Transactional annotation you add to your EventRepo will be overridden by the #Transactional annotation mentioned above in the CRUD methods. Having said that, I really doubt #Transactional annotation has any effect in JpaRepository methods. It would have in your own custom methods, but it seems to me that it has none in the inherited methods.
In order to apply your own transactional settings in EventRepo#save override the save method:
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public interface EventRepo extends JpaRepository<Event, Integer>{
#Override
Event save(Event event);
}
Explanation
Spring ignores your #Transactional annotation because it cannot find the save method in the EventRepo proxy and applies the default transaction settings from the parent CrudRepository interface.
Further reading: How Does Spring #Transactional Really Work?

Creating service instance when needed

I have a Controller class that maps request urls. I have an instance of class annotated with #Service. For example;
#Controller
class MainController{
#Autowired
private UserService userService;
...
}
As I know, this instance is created automatically by Spring container, because I added #Autowired but I use this instance when condition is met in the method. If the condition is not met, I do not need this instance. Thus, this declaration is overhead. I mean, I may not use it even though it is created.
I would like to create the object when it is needed. How can I do this in the code? I probably will not use #Autowired because I need a dynamic object creation. What else do I need to do?
You can use Setter injection. The #Autowired annotation can be used on setter methods. In the below example, when the annotation is used on the setter method, the setter will be called with the instance of FooFormatter when FooService is created:
public class FooService {
private FooFormatter fooFormatter;
#Autowired
public void setFooFormatter(FooFormatter fooFormatter) {
this.fooFormatter = fooFormatter;
}
}
In this way you can inject you service when you call the setter method explicitly :) Hope this will help you :)
LATER EDIT
I've just found a way that might resolve your problem, it's named #Lazy.
You can use #Lazy annotation like this:
On your service class, put #Lazy annotation before the public Class XXX definition;
When declaring/autowiring a Service type in your controller context, put #Lazy annotation with #Autowired annotation on top of the declared attribute like
#Lazy
#Autowired
private FooFormatter fooFormatter;
for more info, check the link: http://www.baeldung.com/spring-lazy-annotation
You need to use #Lazy annotation with a combination of Bean Life Cycle annotations. But one thing you need to consider is the performance of your controller if you will re-create your service each time you need it, then you degradates the performance.

#Transactional in a service class with no call to database

When a service class has no implementation of Jpa repository ,My understanding is that it is wrong to annotate it with Transactional, for example this service class with should not have #Transactional
#Service
public class BillingAddressServiceImpl implements BillingAddressService {
public BillingAddress setByUserBilling(UserBilling userBilling, BillingAddress billingAddress) throws DataAccessException
{
billingAddress.setBillingAddressName(userBilling.getUserBillingName());
billingAddress.setBillingAddressStreet1(userBilling.getUserBillingStreet1());
billingAddress.setBillingAddressStreet2(userBilling.getUserBillingStreet2());
billingAddress.setBillingAddressCity(userBilling.getUserBillingCity());
billingAddress.setBillingAddressState(userBilling.getUserBillingState());
billingAddress.setBillingAddressCountry(userBilling.getUserBillingCountry());
billingAddress.setBillingAddressZipCode(userBilling.getUserBillingZipCode());
return billingAddress;
}
}
The Transactional annotation stands for declaring the database transaction handling of Spring bean methods.
Since your service method is not working with the database it makes no sense to declare a transaction handling.
Transactional annotations are only used with method or classes that makes calls to database,one of the uses of transactional annotation is rollback - which means when we make call to a database there would be a recording of the intermidiate state between the successful call and its original state, this is so that in the case of a failed call the system does not crash but is able to return to its original state

#Caching #CacheEvict not working from AOP (or component)

I was wandering why my #Caching #CacheEvict annotations doesn't do anything when I put it in #Aspect which also has #component annotation.
Is it relates to the fact that this is a #Compnent? or #Aspect?
what am I missing?
#Aspect
#Component
public class cacheAspect {
#After("#annotation(cacheEvictAnnotation)")
public Object clearCachePoint(UHQueryCacheEvict uhQueryCacheEvict) throws Throwable {
evict();
}
#Caching (evict = { #CacheEvict(value= "some_key", allEntries=true) })
evict(){
}
}
when the aspect is running, it will enter the method evict but will ignore the annotation. which means the cache will not get evicted.
Note: the aspect will be triggered on every method in the code which has #cacheEvictAnnotation* annotation. (which is usually in a service method)
As commented, the issue comes from having the evict() method called directly from clearCachePoint which will prevent any aspect like behaviour to happen.
When annotations are enforced at runtime by wrapping concrete types with the required behaviour through proxying, you cannot call methods from the same type and expect to go through the proxy.

Resources