#Transactional not working from scheduled method - java

I have two classess as below.
#Component
#RequiredArgsConstructor
public class SomeScheduler {
private final SomeService someService;
#Scheduled( ... )
void doScheduledJob() {
someService.doJob();
}
}
#Service
#RequiredArgsConstructor
#Transactional
public class SomeService {
private final SomeRepository someRepository;
public void doJob() {
someRepository.findByCustomized();
...
}
}
The problem is that SomeService is working without #Transactional.
With configuration in application.yml logging.level.org.springframework.transactional.interceptor: DEBUG, I found that there are some logs like No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByCustomized]: This method is not transactional.
What I wanna know is :
There is no transctional on service method. Why ? (If I change with MANDATORY propagation, it throws exception)
my repository method which has #Query annotation works. I've thought that 'JPA requires transaction' but it wasn't. Why ?
I've searched this for a while, but couldn't understand. Can any one explain this or show me any article about ?
Thank you.

looks like "findByCustomized" is a non-modifiable query method (aka select), there is no need in transaction thus

Related

How can I use a JpaRepository, with #Autowired, inside a service class?

I've already read these questions and none of them worked:
Spring boot MVC - Unable to Autowire Repository in the service class
Why can't #Autowired a JPA repository - Spring boot + JPA
JpaRepository getting Null at service class
And also this one: https://www.baeldung.com/spring-autowired-field-null
Unfortunately, none of them worked.
What I have is:
Service interface:
#Service
public interface DayTradeService {
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens);
}
Service Implementation:
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
My DayTradeRepository:
#Repository
public interface DayTradeRepository extends JpaRepository<DayTrade, Integer> {}
Inside my DayTradeController (annotated with #Controller), I can use a dayTradeRepository with #Autowired. But inside a service class, I cannot use. I get this message:
Cannot invoke "meca.irpf.Repositories.DayTradeRepository.getDayTrades()" because "this.dayTradeRepository" is null"
How can I make it possible?
EDIT after I accepted Nikita's answer:
I didn't post the Controller code, but it didn't have the #Autowired for the service class DayTradeServiceImpl. That was the point I was missing. After Nikita pointing that, I could solve the problem.
You not need create new object. You have to call like this:
#Controller
#RequestMapping("/test")
public class TestController {
#Autowired
private DayTradeServiceImpl dayTradeService;
#GetMapping(value = "/get")
public void getTrades() {
dayTradeService.getDayTrades(...);
}
}
And set annotation #Service for DayTradeServiceImpl.
#Service
public class DayTradeServiceImpl implements DayTradeService {
#Autowired
private DayTradeRepository dayTradeRepository;
#Override
public List<DayTrade> getDayTrades(List<NotaDeCorretagem> corretagens) {
// Several lines of code and some of them is trying to use dayTradeRepository.
}
}
Spring framework use inversion of control, which has container for beans. For detect beans use annotation like: #Service, #Component, #Repository.

#Transactional annotation overwrites Mockito's InjectMocks

In class TeacherDao method create() calls AddressDao.create():
public void create(Teacher teacher) {
addressDao.create(teacher.getAddress());
// Teacher is being written to database...
}
I am writing a Junit5 test for TeacherDao class, so AddressDao is replaced with a mock.
I call TeacherDao.create() and verify that AddressDao.create() is being interacted:
#Mock
private AddressDao addressDao;
#InjectMocks
#Autowired
private TeacherDao teacherDao;
#Test
void teacherDaoCreateTest() {
teacherDao.create(teacher);
verify(addressDao).create(testAddress);
}
Verification is successful.
After that I add #Transactional annotation to TeacherDao.create() method, and test fails.
AddressDao mock now has zero interactions, and testAddress is being actually written to the database.
I don't totally understand how #Transactional works in-depth and must be missing something important. Why #Transactional rewrites mocks?
I think you should delete the #Autowired annotation.

Constructor of Spring Boot RestController not invoked when using aspect

I am new to AOP and currently trying to implement an aspect for controller methods annotated with a custom annotation.
I allways get a NullPointerException on repository when myFunction is invoked. It seems that i have two instances of of the controller. One of them is instantiated without autowiring the repository. When i remove #MyAnnotation everything works as expected.
Can you give me any hint on how to force Spring/AspectJ to use my constructor?
My controller looks like:
#RestController
#RequestMapping(value = "/api")
public class MyController {
private Repository repository;
public MyController(Repository repository) {
this.repository = repository;
}
#RequestMapping(value = "/{variable1}", method = GET)
#MyAnnotation
public final FeatureCollection myFunction(
final #PathVariable(required = true) long variable1
) {
repository.findById(variable1);
(...)
}
}
The aspect:
#Aspect
public class MyAspect {
#Around("#annotation(MyAnnotation)")
public Object any(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
The configuration:
#Configuration
#EnableAspectJAutoProxy
public class WebConfig {
#Bean
public MyAspect myAspect() {
return new MyAspect();
}
}
Try to Annotate Constructor with #Autowired
#Autowired
public MyController(Repository repository) {
this.repository = repository;
}
It comes from the fact that the annotated method is final.
If you can remove the final keyword, it'll work.
If you google something like "spring aop final methods", you'll find more info, but basically, when Spring creates the proxy, it generates a subclass from your original class, to wrap the call to super with your aspect. The problem is that a final method cannot be inherited by the subclass, so that makes it hard for the proxy to work. Therefore, a lot of limitations come from that, and AOP doesn't work that much with final stuff.
This limitation is mentioned in the docs, I don't think you'll get a workaround for it:
11.6 Proxying mechanisms
...
final methods cannot be advised, as they cannot be overridden.
Hoping this will help you!

Spring: Adding Transaction Specific Resource

I am trying to find a way to add/get a resource/state to an existing transaction. Is this possible in Spring?
What I'm trying to achieve is similar to the pseudo code below:
#Service
#Transactional("txManager")
public class ServiceImpl implements Service {
#Override
#AddResourceHere
public TestObj doSomething(){
...
}
#Override
#AddResourceHere
public TestObj doSomethingAgain(){
...
}
}
#Aspect
#Component
public class Interceptor {
private static final Logger logger = LogManager.get(Interceptor.class);
#Before("#annotation(my.package.AddResourceHere)")
public void switchDatabase(JoinPoint joinPoint){
MyResource resource = TransactionResouceAdder.getResource("transactionSpecificResource");
if(resource == null){
TransactionResouceAdder.addResource(new MyResource("A new resource"));
...
}
else
log.info("resource has already been added for this transaction");
}
}
public class Test {
...
#Test
#Transactional("txManager")
public void doSomethingTest(){
serviceImpl.doSomething();
serviceImpl.doSomethingAgain();
}
}
I found something similar
org.springframework.transaction.support.TransactionSynchronizationManager#getResouce(Object)
org.springframework.transaction.support.TransactionSynchronizationManager#bindResource(Object, Object)
However, this adds a resource to the current thread of the transaction. Is there a way to make the resource transaction bounded only?
In my actual code, I am using spring jdbc's DataSourceTransactionManager as the transaction manager.
Thanks in advance for any help :)
TransactionSynchronizationManager was designed for this purpose and resources are cleared at the end of a transaction (see AbstractPlatformTransactionManager). You'd have to hook it up to your custom annotation with an aspect, but it looks like you already know how to do that.

Injecting multiple dao into one service

if I have several DAOs to be injected into a Service that need to work together in a single transaction, how can I do this ?
#Component
public class CallerClass{
#Autowired
private TransactionClass1 class1;
#Autowired
private TransactionClass2 class2;
public void saveOperation(){
try{
class1.save();
class2.save();
}catch(Exception ex){
}
}
}
Like above simple codes. However, this code is lack
You would just inject all the DAOs in the same manner as you do normally i.e. setter or constructor using #Inject or #Autowired.
You then annotate your service method as Transactional and invoke the required operations on the multiple DAOs. The transaction will encompass all of the dao calls within it.
#Transactional
public void doStuff() {
dao1.doStuff();
dao2.doStuff();
}
You must open the transaction before you use the first dao (For example with #Transactional).
public class MyService{
#Inject
Dao1 dao1;
#Inject
Dao2 dao2;
#Transactional
public doStuffInOneTransaction{
Object x = dao1.load();
Object y = doSomething(x);
dao2.save(y);
}
}
Do you use JTA? Do you implement your transactions on your own? Please provide more information about your architecture so we can respond accordingly.
EDIT:
Check this one out, for example:
http://community.jboss.org/wiki/OpenSessionInView

Categories