Why do we need to annotate the Service class with #Transactional in Spring Data JPA - spring-boot

In a spring boot app, we have user-defined repository interface that extends JpaRepository.
JpaRepository in turn is has an implementation class SimpleJpaRepository.
SimpleJPARepository has 2 annotations on it
#Transactional
#Repository
So we can skip these 2 annotations on our user-defined repository interface that extends JpaRepository.
Then why do we need to explicitly add #Transactional over service class which is also using our user-defined repository object only?

The point of having the Transactional annotation is so that everything in the annotated method occurs within the same unit of work and either everything succeeds or everything fails. Putting Transactional only on each repository means each repository can have its own transaction, and the second one failing doesn't rollback the first one.
You can have nontransactional methods on a service, or every method so annotating a class as a Service doesn't mean spring can assume everything is transactional.

This is a has vs is problem.
An object can be Transactional, or have a member object that is Transactional.
If the object has a member object that is Transactional, it is not automatically Transactional itself.
Object A contains Object B which is Transactional, that does not make Object A Transactional.

Related

Transaction - Springboot(JHipster) - RestService: how to

I have a microservice created with JHipster(SpringBoot+JPA) exposing a rest api.
During a save operation over an Entity I need to manage the transaction because I must execute another update over the DB (using other Entities).
How can I do this?
Using the tradictional approach (JDBC) I got the connection and create a transaction over it, make all the queries and finally close the transaction(commit/rollback).
With JPA I have an Entity, but I find no way to specify to begin/end(manage) the transaction programmatically.
You have many alternatives, here are few ones:
define a service (a class annotated with #Service) and annotate with #Transactional the public method that implements your logic
manage transaction manually through the EntityManager injected into your service class constructor
create a custom Repository
Check the Spring docs

#Controller, #Service, #Repository beans fails on #EnableTransactionManagement in mode = AdviceMode.PROXY or default fails

Why using #EnableTransactionManagement in default mode or PROXY mode attempts against beans creation like #Controller, #Service, and #Repositories. I don't discard another kind of beans targeting this bad behavior.
I have a project with:
SpringBoot 2.1.8.RELEASE + JPA + Rest Controller
PostgreSQL 9.6
#Transactional annotation on methods like save, update and delete (also, batch delete)
It creates proxy classes and nulls the remaining beans in the ApplicationContext.
The default mode is PROXY. When ASPECTJ advice mode is set, all the beans are injected in the right place. Check Spring current docs on the subject.
The mode() attribute controls how advice is applied: If the mode is AdviceMode.PROXY (the default), then the other attributes control the behavior of the proxying. Please note that proxy mode allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
Note that if the mode() is set to AdviceMode.ASPECTJ, then the value of the proxyTargetClass() attribute will be ignored. Note also that in this case the spring-aspects module JAR must be present on the classpath, with compile-time weaving or load-time weaving applying the aspect to the affected classes. There is no proxy involved in such a scenario; local calls will be intercepted as well.
Like this:
Still, #Transactional methods fail. Due to "TransactionRequiredException", so ASPECTJ does not solve the problem in persistence layer, only grants beans injection (maybe no platform transaction manager is created). What to do next?
See the transaction exception:
!!! Solution:
When working with transactions, the scope has to be shared in the beans chain: #Service(also, caller method)<-#Repository(also, transactional method), #Service context (class, method) shall be marked as #Transactional. Applies to annotated methods or classes in the call stack that ends in transactional operation (bottom-up approach).
Annotation sequence:
#EnableTransactionManagement (in #Configuration alike classes or #SpringBootApplication -autoconfiguration-)
#Transactional annotated method/classes in beans injection chain (bottom-up: persistent method/class, then #Service/#Component layers)
#Autowired annotation on beans candidates (Service instance in #Controller class, Repository instance in #Service class)
Note: Spring AOP does not create proxy properties from functional interfaces based features, only object instances so recommended is using methods encapsulating persistence logic.
e.g
Function<T, R> function
BiFunction<T1,T2,R> function
Supplier<T> supplier
...

How can I replicate the rollback from Entity Manager with JPA Repository?

I am converting a project from Spring framework to Spring boot, so I am no longer using persistence files and other config files.
Also, I gave up using Entity Manager, instead I created repositories which extend JPA Repository, so that I can use the functions from there. The only thing is that I have some unit tests and in the Spring framework, at the end of each test there is a finally clause which has a rollback, so that the data from the database to be specific to each test.
How can I do that without Entity Manager? I tried using the flush() method, but no result...
By default, data JPA tests are transactional and roll back at the end of each test.
You can refer to Enabling and Disabling Transactions in spring test documentation which indicate :
Annotating a test method with #Transactional causes the test to be run within a transaction that is, by default, automatically rolled back after completion of the test. If a test class is annotated with #Transactional, each test method within that class hierarchy runs within a transaction. Test methods that are not annotated with #Transactional (at the class or method level) are not run within a transaction. Furthermore, tests that are annotated with #Transactional but have the propagation type set to NOT_SUPPORTED are not run within a transaction.
Tips :
If you want to commit the transaction for a reason or another, you can use the #Commit annotation or less properly #Rollback(false) on method or class level.
If you want to execute code outside of a transaction ( before or after ) you can use #BeforeTransaction and #AfterTransaction on public methods that have no return ( return void ) or on default method of interfaces.

Why doesnt #Transactional and #RequestMapping work together?

The moment I include the #Transactional annotation on a #RequestMapping, I notice in springboot that the url mappings do not auto-configure.
What could be responsible for this?
I want a case where (C)R(UD) rest calls work within a transaction.
If you're goal is to ensure your CRUD operations happen within a transaction, then using Spring Data JPA, this is done for you by default. Creating a repository interface that extends CrudRepository for example, your query methods will inherently be #Transactional. You can customize the #Transactional attributes by manually annotating a query method on your repository, but this need only be done if you want non default behaviour.
See the Spring Data JPA docs for more details.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions

Autowired spring bean is not a proxy

I'm working on a very small application connecting to a MySQL database.
I'm trying to create table record but getting 'no transaction in progress'.
I have all the right stuff in place:
a service interface MyService and its implementation MyServiceImpl
I have annotated the service impl with #Service
In the controller I used the interface name for the field #Autowired MyService
I have the correct transaction configuration as it was originally generated by roo
There is a public method MyService.create(...) which MyServiceImpl implements
But,
When I remote debug and inspect the controller's myService field what I see is something like
com.some.package.services.MyService#12345 (and NOT something like $Proxy73) which to me is not right, because what should be autowired is the proxy not he target bean (which is what I think this is). If I'm correct then it makes sense that there is no transaction as the annotation would only kick in when invoking a public method annotated with #Transactional on a proxy.
Please tell me why is spring injecting the target bean in this setup.
Thanks
If you have AspectJ-enabled transaction management (<tx:annotation-driven mode="aspectj" .../>) application of transactions happens in-place in the same class, either during build (compile-time weaving) or on startup (load-time weaving).
No new classes are created (like when using cglib) and no proxies (like with ordinary interface-based AOP in Spring). Instead bytecode of MyServiceImpl was modified directly without you even noticing. Unfortunately the only way to see AOP is to decompile your classes. If you use javap -c MyServiceImpl you'll find plenty of references to Spring transaction layer.
If you are using Spring MVC, make sure to scan specific controller classes alone in servlet context file. Otherwise it will scan 2 times and transaction is not available on the application context.

Resources