Run part of a method under spring transaction - spring

I have a method that does something like this
class EmployeeService {
#Transactional
public void perform() {
// perform DB operations()
createEmployee()
// call some async service that relies on the persisted data
runEmployeeBGV();
}
}
runEmployeeBGV() crates a separate thread which does bgv operations.
I want data to be persisted as soon as the createEmployee() method ends. But due to limitations on #Transactional(and my knowldge), I am not sure on how to exclude runEmployeeBGV() out of the scope of transaction.
Please note that these two operations need to reside within perform() method which is being called by another service class where EmployeeService is injected.
Is there any way we can achieve this without calling these methods separately from the client code?

You can move those methods to another service and move #Transaction to createEmployee()
something like that
class EmployeeService {
private EmployeeRepo repo;
private EmployeeBGV bgv;
public void perform() {
repo.createEmployee()
bgv.runEmployeeBGV();
}
}
class EmployeeRepo {
#Transactional
public void perform() {
//code
}
}

Related

Transactional and Stream in Spring

I try to understand why this code doesn't work
In component:
#PostConstruct
public void runAtStart(){
testStream();
}
#Transactional(readOnly = true)
public void testStream(){
try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
top10ByFirstName.forEach(System.out::println);
}
}
And repository :
public interface PersonRepository extends JpaRepository<Person, Long> {
Stream<Person> findTop10ByFirstName(String firstName);
}
I get:
org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses #Transactional or any other way of declaring a (read-only) transaction.
One key thing about Spring is that many annotated features use proxies to provide the annotation functionality. That is #Transactional, #Cacheable and #Async all rely on Spring detecting those annotations and wrapping those beans in a proxy bean.
That being the case, a proxied method can only be used when invoked on the class and not from within the class. See this about the topic.
Try:
Refactoring and call this #Transactional method from another class in your context, or
By self-autowiring the class into itself and calling the #Transactional method that way.
To demonstrate (1):
public class MyOtherClass {
#Autowired
private MyTestStreamClass myTestStreamClass;
#PostConstruct
public void runAtStart(){
// This will invoke the proxied interceptors for `#Transactional`
myTestStreamClass.testStream();
}
}
To demonstrate (2):
#Component
public class MyTestStreamClass {
#Autowired
private MyTestStreamClass myTestStreamClass;
#PostConstruct
public void runAtStart(){
// This will invoke the proxied interceptors for `#Transactional` since it's self-autowired
myTestStreamClass.testStream();
}
#Transactional(readOnly = true)
public void testStream(){
try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
top10ByFirstName.forEach(System.out::println);
}
}
}

Will invoking two methods on #Stateless use the same instance?

If I have something like this-
#Stateless
public class EJBServcie{
public void method1(){
// some code goes here
}
public void method2(){
// some code goes here
}
}
with the bean using it as-
public class Bean{
#EJB
EJBService ejbService;
punlic void action(){
ejbService.method1();
ejbService.method2();
}
}
In this example, method1 is invoked on an instance of EJBService. Will method2 be invoked on the same instance?
The EJB container might choose to use the same instance depending on pooling configuration or concurrent calls, but there is no guarantee: it could choose to use a different instance for each call.

Spring #Async #Autowired null in only one method

I am encountering a NullPointerException in my Spring application when calling a method on an autowired object. The class in question looks like the following:
#Component
public class Listener {
#Autowired
TemplateService templateService;
#Async
#EventListener
private Future<String> listener1(Event1 event) {
System.out.println(templateService);
return new AsyncResult<>(null);
}
#Async
#EventListener
public Future<String> listener2(Event2 event) {
System.out.println(templateService);
return new AsyncResult<>(null);
}
}
When I publish an event that triggers listener1, a null value is printed, but when I publish an event that triggers listener2, the toString() method of TemplateService is called (as I would expect). I'm probably misunderstanding some aspect of how #Async affects #Autowired objects, but I haven't been able to determine what that would be. Am I misusing #Async? Am I misunderstanding how to use #Autowired objects in a multithreaded environment?
Change the visibility of your listener1 method to be at least protected (package visibility , protected or public). This is because Spring creates a proxy which is a subclass of your component. It overrides your #Async annotated methods in order to add new logic to execute your code in a separate thread. However because it uses inheritance it can only override methods which are visible to the subclass.
This explains why listener2 method which is public works.
Change your method to
#Async
#EventListener
public Future<String> listener1(Event1 event) {
System.out.println(templateService);
return new AsyncResult<>(null);
}
Spring needs an interface to create a proxy class. It's this proxy class that gets called every time you call the method, and it's through this method that the whole asynchronous execution happens. Without an interface Spring can't autowire, scan or make methods execute asynchronously.
public interface Listener {
public Future<String> listener1(Event1 event);
public Future<String> listener2(Event2 event);
}
#Component
public class ListenerImpl {
#Autowired
private TemplateService templateService;
#Async
#Override
public Future<String> listener1(Event1 event) {
System.out.println(templateService);
return new AsyncResult<>(null);
}
#Async
#Override
public Future<String> listener2(Event2 event) {
System.out.println(templateService);
return new AsyncResult<>(null);
}
}
It's also worth noting that Spring can't run private methods asynchronously.

Where should we use #Transactional and where is Service layer?

I have rest style controller in Spring. In controller I have injected dao interfaces. From controller I persist data. In the other words, I have like REST web service. people sends me data, and I persits it.
/**
* Payment rest controller which receives
* JSON of data
*/
#Controller
#RequestMapping("/data")
public class PaymentTransaction {
#Autowired
private TestDao dao;
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody()
public String test(HttpServletRequest request) {
...
}
At the moment I have #transaction annotation in Dao classes. For instance:
import org.springframework.transaction.annotation.Transactional;
#Component
#Transactional
public interface TestDao {
#Transactional(propagation = Propagation.REQUIRED)
public void first();
}
I have read that this is very bad style. Using this answer at stackoverflow , here is explain and examples why is this bad - we must not add this annotation in DAO and in controller too. We must add it in service layer.
But I don't understand what is the service layer? Or where is it? I do not have anything like this.
where should I write #Transactional annotation?
Best regards,
According to the cited post, you should design your classes somehow like this (rather pseudocode):
controller (responsible for handling clients' requests/responses)
#Controller
#RequestMapping("/data")
public class TestREST {
#Autowired
private TestService service;
public void storePayment(PaymentDTO dto) {
service.storePayment(dto); //request from a client
}
public PaymentDTO getPayment(int paymentId) {
return service.getPayment(paymentId); //response to a client
}
}
service layer (also called business layer, responsible for business logic - knows what to do with incoming messages, but does not know where they come from).
public class TestServiceImpl {
#Autowired
private TestDao dao;
#Transactional(propagation=Propagation.REQUIRED) //force transaction
public void storePayment(PaymentDTO paymentDto) {
// transform dto -> entity
dao.storePayment(paymentEntity); //read-write hence transaction is on
}
#Transactional(propagation=Propagation.NOT_SUPPORTED) //avoid transaction
public Payment getPayment(int paymentId) {
return dao.findPayment(paymentId); //read-only hence no transaction
}
}
data access layer (also called persistence layer, responsible for accessing database - knows how to use entity model / ORM, does not know anything about the upper service layer)
public class TestDAOImpl {
#PersistenceContext
private EntityManager em;
public void storePayment(PaymentEntity paymentEntity) {
em.persist(paymentEntity);
}
public PaymentEntity getPayment(int paymentId) {
return em.find(PaymentEntity.class, paymentId);
}
}
By this approach you get separation of concerns mentioned in the post. From the other hand such an approach (business layer vs data access layer) got a little dose of criticism from Adam Bien's on his blog ("JPA/EJB3 killed the DAO"). As you can see there is no a single solution for the problem, but I encourage to read some other opinions and apply the solution you find the most suitable for your needs.
When you call two Dao methods first & second from controller, 2 transactions will be done, one with starts before first method and ends after it's execution and the second one starts before second method starts and ends after it's execution. Whereas you create an additional class in between controller and dao (usually this is called service layer) and annotate it with #Transactional and call multiple Dao methods in it, a transaction is started at the start of service method and all the dao calls will be executed and transaction will be closed, which is what you require. And inject the Service into Controller.
Controller -> Service -> Dao
#Controller
#RequestMapping("/data")
public class PaymentTransaction {
#Autowired
private TestService service;
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody()
public String test(HttpServletRequest request) {
...
}
}
#Service
#Transactional
public class TestService {
#Autowired
private TestDao dao;
#Transactional
public void serviceCall(){
dao.first();
dao.second();
}
}

Trigger a second advised method from a method already being advised in Spring

I have a Class, call it X, in this class I have successfully advised a method call it method(){} from an Annotated Spring.
So, here it is:
public class X {
public void method(){...}
public void method2(){...}
}
Here is my aspect, shortened of course:
#Aspect
public class MyAspect{
#Pointcut("execution(* X.method(..))")
public void methodJP(){}
#Pointcut("execution(* X.method2(..))")
public void method2JP(){}
#Around("methodJP()")
public void doMethodJP(ProceedingJoinPoint pjp) throws Exception {
pjp.proceed(); //Amongst other things!!!
}
#After("method2JP()")
public void doMethod2JP(JoinPoint jp) throws Exception {
//Do some stuff here
}
}
Now... both join points work well, however, I within my X.method, I also call the method that is advised by method2JP()... and of course, my method2JP does not get triggered.
Is there any way I can get this to work?
Thanks.
Since Spring AOP works by proxying classes, for the advice to be invoked, you must call the method through the proxy or wrapper supplied by the bean factory.
If you don't want to break out into multiple classes, you can have the method retrieve a the proxied version of "itself" from the beanfactory. Something like this
#Service
public class MyService {
#Autowired
ApplicationContext context;
public void method1() {
context.getBean(MyService.class).method2();
}
public void method2() {
}
}
This will guarantee that the invocation of method2 from method1 will apply any aspects on the method2 pointcut.
methodJP() should be declared in another class. In the regular scenario the aspects are not triggered when you invoke a method from within the same object.

Resources