Spring #Transactional changed behavior after update - spring

I ve a spring project which is already in production since years. After the Spring update from 2.3 to 2.7 the #Transactional services changed their behavior. Two scenarios:
Api-service-service-repo, on the interfaces from the services
After the update i got a „rollback exception“ so i added Transactional to the Api and it works again.
Lazy loading initialization in the transactional service, when accessing a lazy loaded getter. For example getreferencebyid() and accessing the getter throws the exception. So i added an own query with entitygraph and load the data explicit it works.
Im doing something wrong or changed something in the spring versions?

Related

No existing transaction found for transaction marked with propagation 'mandatory'

This is somewhat weird behavior. I moved from Spring MVC to Spring Boot Configuration. This has caused the #Transactional method to throw the above error. Not sure why would switching from MVC to boot mvc do that. Anyone having nay idea about this?
I don't have specific code snippet as this is application wide and was working fine till I had Spring MVC. Now I moved to Spring Boot (Dependency upg. Filters moved etc.)
Flow for the methods having #Transactional is:
Action is called
If contains execute() which calls a Save method with #Transactional from a class which is implementation of an interface.
This class have another Dao method having #Transactional.
Thanks

#SpringBootTest loads unrequired Bean when making IT

I'm making some Integration Tests for my app and I'm encountering this problem I can't see how to solve.
I'm using Spring Boot 2.4.13 + Spring Data Neo4J 6.1.9
FYI, I deleted the Application default test that comes bundled when you create a project through Spring Initializr, and under /src/test/resources I have a .yml file named application.yml
My IT class looks like this:
#SpringBootTest
public class ClientIT {
#Autowired
private ClientServiceImpl service;
#Autowired
private ClientRepository repository;
#Test
void someTest() {
//Given
//When
//Then
}
}
But when I run this test I get the following Exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
And this is the cause:
Caused by: java.lang.IllegalStateException: The provided database selection provider differs from the ReactiveNeo4jClient's one.
The thing is I don't use SDN's Reactive features at all in my project. I don't even understand why Spring tries to load it. I've created an Issue under the Spring Data Neo4j GitHub repository (https://github.com/spring-projects/spring-data-neo4j/issues/2488) but they could only tell me that ReactiveNeo4jDataAutoConfiguration gets automatically included if there's a Driver or Flux class in the classpath which I don't have.
I've been debugging the Spring internals while booting up the Application after JUnit Jupiter methods to no success.
What I could see is that at some point after JUnit Jupiter tests preparation/initialization, "reactiveNeo4jTemplate" gets injected into DefaultListableBeanFactory's beanDefinitionNames variable.
I've tried many combinations of different annotations intended to be used when making Integration Tests but the one time it worked was after I explicitly excluded ReactiveNeo4jDataAutoConfiguration class through
#EnableAutoConfiguration(exclude=ReactiveNeo4jDataAutoConfiguration.class)
What I've always seen in some blogposts is that by using #SpringBootTest I shouldn't worry about this kind of problem but it looks like I need to add that annotation every time I want to make a new IT test.
My Integration Tests basically consist of bootstrapping the application + web server (tomcat) along with an embedded Neo4J instance and after that, making requests to check everything works as it should. Do I really need to worry about all of this just to make these simple tests?
Thank you
References:
How do I set up a Spring Data Neo4j integration test with JUnit 5 (in Kotlin)?
SprintBootTest - create only necessary beans
Answering my own question after finding what is causing this error:
In the linked Github Issue, one of the developers says having Flux.class in the classpath forces SDN to instantiate Neo4jReactiveDataAutoConfiguration which is what is causing the other reactive beans to instantiate.
Apparently, neo4j-harness brings io.projectreactor (where Flux.class belongs) as an indirect dependency through neo4j-fabric which is the root of our problems.
The Spring Data Neo4j will be fixing this issue in a patch later this week.

#Transactional doesnt work whereas DefaultTransactionDefinition works

I am upgrading my application from Spring3 to Spring 4. In my existing application we were using OpenSessionInViewInterceptor which creates the transaction along with new request.
Now I am using JPA also so even if I use OpenEntityManagerInViewInterceptor it doesn't associate transactions with it. So I had to put transaction manually in all my controller methods.
Due to legacy code, the controller classes have lots of business logic instead of distributing it properly to service layer.
Now if I put #Transctional annotation on controller method, then it doesn't work whereas if I use manual transaction through DefaultTransactionDefinition then it works properly.
Also, if I remove the business logic of controller methods to service layer, and put #Transactional annotation to service layer, then it also work fine. But these changes are tedious and my application is very big, so cant do it.
Please let me know why #Transactional doesn't work in my case if I put it in controller, how should I get it working.
I am not using AspectJ for transaction management.
Tried approaches:
Code at both places : code in dispatcher-servlet.xml along with appliacationContext.xml but still the controller transactions are failing.
Moved bean for urlMapping into applicationContext.xml but still it fails.

Lazy loading works, but shouldn't

The context of this question is within spring-boot, using spring-data-jpa and hibernate.
A colleague wrote an #Service and annotated the service method with #Transactional. The service method loads an entity, and subsequently hits a one-to-many lazily loaded collection (fetch = FetchType.LAZY). The service method is invoked by some custom delegator, which i will come back to. This works fine when invoked from a #RestController endpoint.
When i invoked the service from a camel route (again via the custom delegator) it barfed with a lazy initialization exception.
On digging, found that the service implements an interface, the custom delegator looks up the service (it is injected so has proper proxy) and calls a method
on the interface which is actually a java-8 default method. This default-method then locally calls the #Transactional method.
So there's the problem :- this is a LOCAL method call so the aspecting/proxy-ing of the #Transactional annotation is not done (we use aspectJAutoProxy) so the method is NOT invoked within a transaction, so the lazy-loading SHOULD fail. And to double-check, also tried it via an #Scheduled annotation: same behaviour. Barfs like it should.
My Question: So why does it work when called from the #RestController? This is driving me nuts!
There is no transactional annotation on the rest controller endpoint.
I added some debug code to the service using TransactionSynchronizationManager.isActualTransactionActive() and it shows that in no case is there a transaction, even when being called via the controller endpoint.
So why does the lazy loading work when being called from the controller?
I dumped all SQL and at no points are the lazy-collection already loaded, so they are not in any hibernate cache.
I remember reading once that lazy loading was a hint, not a command, but still... why does it work in that one case?
after being perplexed by this on many occasions, have stumbled across the answer:
sprint-boot is doing an open-entity-manager-in-view behind our backs via the OpenEntityManagerInView interceptor. Had no idea this was going on.
See this excellent answer from Vlad Mihalcea https://stackoverflow.com/a/48222934/208687
When your method annotate to transactional hibernate session close after return method , if object that return from method have lazy , lazy property not load and you get exception that session close. You can use fetch in query or using OSIV

How do I change my configuration to a different data source?

I went through the Data Access With Spring tutorial and the in memory database they use in step 3 is working. But, I'm not clear on what I need to add/change to get it to query my development (Oracle) database now?
I want to use Hibernate, do I still need this JPAConfiguration class or would I have something Hibernate specific?
Please don't just post a link to the Hibernate reference. I'm reviewing that as well, but since I'm also using Spring, it's not clear to me the proper way to load the hibernate.cfg.xml and inject the Hibernate session in that context.
Don't be blocked by the fact that the class is called JPAConfiguration. You need to understand what the class does. Note that it has the annotation #Configuration which you can use along with AnnotationConfigApplicationContext to produce a Spring bean context.
That functionality is described in the Spring documentation for The IoC container.
What you need to change is how your DataSource and EntityManagerFactory beans are created. You'll need to use a DataSource that gets Connection instances from a JDBC Driver that supports Oracle databases.

Resources