Execute a method once every transaction begins inside methods annotated with spring - #Transactional - spring

I want to make a database call before every method within my Spring application annotated with #Transactional started executing transaction.
There are few requirements for this:
This database call has to be part of the actual transaction that is about to begin.
The database connection used for the Transaction has to be same to be used for this database call and should setup some database data before 'real' transaction begins.
Is there something that Spring supports to achieve this goal ? One way I am thinking is to write own Aspect cloning more or less all Transactional code as is. Other way is to write Aspect. Not sure if there are more ways.

Related

Spring boot app, need to set a database session variable before every transaction

I have a spring boot application that uses Hibernate/JPA entities. I need to run a bit of SQL to set a database session variable prior to each transaction. This session variable controls row level security at the database layer and so the SQL will use a web session parameter which I can retrieve from the spring web session context. I will need this bit of sql to run essentially before every transaction.
I'd like to be able to do this in a way that does not effect every additional piece of business logic. i.e. I'd rather not have to call the method manually from every repository class.
I saw the ConnectionPreparer class in the spring-data-jdbc-ext project (https://github.com/spring-projects/spring-data-jdbc-ext/blob/master/spring-data-jdbc-core/src/main/java/org/springframework/data/jdbc/support/ConnectionPreparer.java). However it appears this class is only called when the connection is first instantiated, not prior to every transaction.

Spring Boot - Different Testing approaches

I've been working with Spring and Hibernate for about two years. Recently I have also been working on testing. Now I'm not quite sure if I understood everything correctly. Do I understand correctly that the following methods exist? **If I make wrong assumptions, please correct me!
Method 1:
Situation: The test class is annotated with #Transactional. The test data is created manually in an #BeforeEach method and stored in a repository.
Advantages: Through #Transactional annotation, all (BeforeEach, Test-Method, AfterEach) methods are executed in one transaction, which can be undone directly by rollback and therefore no emptying of the database is necessary.
Disadvantages: Since everything is carried out in one transaction and canceled directly by rollback, the data never ends up correctly in the database? Perhaps errors would occur during a commit? This means that the test does not reflect a real situation.
Method 2:
Situation: The test class has no #Transactional annotation. The test data is created and stored in an #BeforeEach method.
Advantages: Since the #Transactional annotation is missing, all calls of the service or controller are executed in a separate transaction, reflecting a real situation.
Disadvantages: Since everything is executed in separate transactions, the database must be completely emptied manually after each test (disable constraints and empty each table).
I have another question, but it's more subjective Do you like the initialization of test data using the #BeforeEach method and manual creation of objects and saving via repository or SQL scripts in #Sql annotation better? Initializing via SQL scripts feels faster in my opinion.

How to keep an EntityManager/Session open across multiple transactions in a single thread?

Is there any way to prevent spring data from closing the underlying hibernate session after an #Transactional method in a #Service component? I am writing a simple command line app that reads data from a web service, does some processing and writes to the database. Some of the operations span multiple entities and must be transactional.
However, I am running into too many LazyLoadingExceptions. Apparently the hibernate session is automatically closed by spring after the transaction commits.
In other words, what I am trying to achieve is something like OpenSessionInView, but for a command line app. I could achieve this by using pure JPA and manually handling the entity manager and transactions. However, I would like to know if is there a solution which enables to leverage the spring-data and still achieve the desired behavior.

Business logic before to save an entity in Spring JPA

I'm using Spring Boot 1.5.4, Spring Data REST, Spring JPA, Hibernate and I'm developing a Angular client consuming REST API.
Spring Data REST helps a lot and I'm trying to follow best practice, so a repository is like:
#Transactional
#PreAuthorize("isAuthenticated()")
public interface CustomerRepository extends PagingAndSortingRepository<Customer, Long> {
}
and automagically I've all my save(), delete(), findXX() methods. That's great.
Now I'm wondering how if I need custom business logic to do before the entity is saved. let's say I need to do some kind of complex validation (involving queries on the db), and other backstage activities (maybe saving related entities, updating related objects, ect).
My goals are:
Ensure every time the entity is saved (either from a REST call or a JPA call) my business logic is called before the object is saved
Avoid to create a custom repository because a developer could call the standard repository breaking my rules
Find a way to do this in a simple way in order to keep the app easy to mantain
The #RepositoryEventHandler is not enough for me because I want ensure my business logic is always verified even when the call to the method come from internal classes.
Could you suggest me the best approach to reach my goals?
JPA has a bunch of entity listener.
#PrePersist Executed before the entity manager persist operation is actually executed or cascaded. This call is synchronous with the persist operation.
#PreRemove Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
#PostPersist Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed.
#PostRemove Executed after the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation.
#PreUpdate Executed before the database UPDATE operation.
#PostUpdate Executed after the database UPDATE operation.
#PostLoad Executed after an entity has been loaded into the current persistence context or an entity has been refreshed.

Is there a better way of detecting if a Spring DB transaction is active than using TransactionSynchronizationManager.isActualTransactionActive()?

I have some legacy code that I am now trying to re-use under Spring. This code is deeply nested in other code so it's not practical to redesign and is called in many situations, only some of which are through Spring. What I'd like to do is to use the Spring transaction if one has been started; otherwise, continue to use the existing (legacy) db connection mechanism. Our first thought was to make our legacy class a bean and use an injected TransactionPlatformManager, but that does not seem to have any methods germane to our situation. Some research showed that Spring has a class called TransactionSynchronizationManager which has a static method isActualTransactionActive(). My testing indicates this method is a reliable way of detecting if a Spring transaction is active:
When called via Spring service without the #Transactional annotation, it returns false
When called via Spring service with #Transactional, it returns true
In my legacy method called the existing way, it returns false
My question: Is there a better way of detecting if a transaction is active?
No better way than the TransactionSynchronizationManager.isActualTransactionActive(). It is the utility method used by spring to handle the transactions. Although it is not advisable to use it within your code, for some specific cases you should - that's why it's public.
Another way might be to use the entity manager / session / connection and check there if there's an existing transaction, but I'd prefer the synchronization manager.

Resources