Is it possible to manage the receipt of a Connection for a transaction in Spring (the mode Open Session in View)? - spring-boot

I use Spring boot to simplify working with the configuration.
When the RestController receives a request for it automatically (this is the default action), Connection is allocated from the datasource and until the transit is completed, Connection is open. (at least I have such information, you can correct it).
In is a mode: Open Session In View.
OSIV in Spring Boot is implemented using the OpenEntityManagerInViewInterceptor web request interceptor class. Unlike pure Spring, it is enabled here by default.
But before executing the transactional method, this request may be delayed on the business logic layer for processing, and the connection is "idle". This leads to Connection leaks.
It seems that you can control the output of connection when using Srpingboot .
But how is this done ?
Please give an example.

First. You should disable the mode Open Session in View.
spring.jpa.open-in-view=false
Then, you should use the #EntityGraph annotation.
public interface UserRepository extends CrudRepository<User, Long> {
#EntityGraph(attributePaths = "departments")
Optional<User> findDetailedByUsername(String username);
Optional<User> findByUsername(String username);
}
Beware of using Hibernate.initialize(), because it forms not one, but several queries to get related tables.

Related

how to Resolve "could not initialize proxy - no session" error when using Spring repository

I'm working on a mutitenant project it maintains different schema for each tenant, followed Project
As we are dynamically switching the tenants so it looks like some configuration is missed which is closing the session or not keeping the session open to fetch the LAZY loaded objects. Which results in "could not initialize proxy - no session" error.
Please check below link to access the complete project and db schema scripts, please follow the steps given in Readme file.
Project
It will be helpful if someone can point out the issue in the code.
i tried to put service methods in #Transactional annotation but that didn't work.
I'm expecting it to make another call to the LAZY loaded object, This project is simplefied verson of the complex project, actually i have lot more lazy loaded objects.
Issue:-
I'm getting no Session error "could not initialize proxy [com.amran.dynamic.multitenant.tenant.entity.Tenant#1] - no Session"
at line 26 (/dynamicmultitenant/src/main/java/com/amran/dynamic/multitenant/tenant/service/ProductServiceImpl.java)
The issue is that your transaction boundaries are not correct. In TenantDatabaseConfig and MasterDatabaseConfig you've correctly added #EnableTransactionManagement, which will setup transactions when requested.
However - the outermost component that has an (implicit) #Transactional annotation is the ProductRepository (by virtue of it being implemented by the SimpleJpaRepository class - which has the annotation applied to it - https://github.com/spring-projects/spring-data-jpa/blob/864c7c454dac61eb602674c4123d84e63f23d766/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L95 )
and so your productRepository.findAll(); call will start a transaction, create a JPA session, run the query, close the session, close the transaction, which means that there is no longer any transaction / session open in which to perform the lazy-loading.
Therefore, your original attempt of
i tried to put service methods in #Transactional annotation but that didn't work.
IS the correct thing to do.
You don't say exactly what you tried to do, and where, but there are a few things that could have gone wrong. Firstly, make sure you're adding a org.springframework.transaction.annotation.Transactional and not a javax.transaction.Transactional annotation.
Secondly (and the more likely problem in this scenario), you'll need to configure the annotation with which transaction manager the transaction should be bound to, otherwise it may use an existing / new transaction created against the master DB connection, not the tenant one.
In this case, I think that:
#Service
#Transactional(transactionManager = "tenantTransactionManager")
public class ProductServiceImpl implements ProductService {
should work for you, and make all the methods of the service be bound to a transaction on the tenant DB connection.
EDIT: Answering a follow-up question:
can you please also suggest a better way to inject my tenantTransactionManager in all my service classes, as I don't want to mention tenantTxnManger in all service classes if there is any better way to do it ?
Yes, sure. You can create a meta-annotation that applies multiple other annotations, so you could create:
/**
* Marks class as being a service operating on a single Tenant
*/
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Service
#Transactional("tenantTransactionManager")
public #interface TenantService {
}
and then you can simply annotate your service classes with #TenantService instead of #Service:
#TenantService
public class ProductServiceImpl implements ProductService {

Spring Data: How to maintain cache consistency in transactional methods?

Let's assume we have a standard Spring Boot application with JPA. We have repositories, services and REST controllers. On the service layer, we have this:
#Service
public class UserService {
#Autowired
private UserRepository userRepo;
#Transactional(readOnly = true)
public User getUserById(userId: String) {
return this.userRepo.findById(userId).orElse(null);
}
#Transactional(readOnly = false)
public User saveUser(User user){
this.userRepo.save(user);
}
}
We want to cache the result of getUserById, either via #Cacheable or via an explicit cache. We have the following two options:
If a call to saveUser(...) occurs, we call repo.save(user) and then we immediately put the saved user into our cache (write-through).
If a call to saveUser(...) occurs, we invalidate the corresponding entry in the cache. Once the user is requested by ID again, we read it from the database and put it into the cache.
Both methods have issues:
If we write-through, we risk that the database transaction fails at some point after the repo.save(user) call and is rolled back. We may have written a version of the user into our cache that never hit the database. Our cache is out-of-sync with the database.
If we only invalidate the cache, there is a time period between the invalidation and the transaction commit where a concurrent transaction may call getUserById(...). This transaction will still read the old version of the user and write it into the cache. The result is that we have outdated data in our cache.
Is the built-in spring cache susceptible to these issues as well? How do you avoid such problems in your application?
Ok so I got confused here. There is the Spring Boot side of caching, which is supposed to cache method results, and then there is the 2nd level cache of the JPA provider. These are different things with different purposes. My bad for mixing them up.

JPA transactional proxy within a thread issue

In my Controller I have injected (#Autowired) this Service, which implements Runnable (I need multi-threading) and I call it like so:
Thread t = new Thread(service);
t.start();
t.join();
Then, in my Service's run() I call this Repository (simple JPARepository), which is injected in Service also with #Autowired:
repository.save(someEntity);
The problem is that it doesn't persist the entity with id=1. The transactional proxy (and Hibernate connection pool) is initialized after the unsuccessful saving of the first entity. After that, it works fine.
Can anyone point me to the right direction with my issue: how to force the Thread to initialize the Hibernate transactional proxy before persisting the first entity?
You should consider to start the thread after Spring context is refreshed. This is safer because all your beans may be in an inconsistent state.
#EventListener(ContextRefreshedEvent.class)
public void handleContextStart() {
// ...
}

Is Entity Manager cleared automatically after each request?

Spring is providing one Entity Manager per thread. But I can`t find info if Spring clears Entity Manager after #RestControllers method is finished executing? So for example, if I have a method similar to this
#GetMapping("/{id}")
public ResponseEntity<SomeEntity> someRequest() {
SomeEntity res = someService.doSomeJpaRelatedWork();
return new ResponseEntity<>(res), HttpStatus.OK);
}
Will spring call EntityManager.clear() after the request or will Entity Manager keep entities for further requests on that thread?
Since your method doesn't use an EntityManager nor has it #Transactional annotation it is completely independent of the EntityManager and will on its own not affect any EntityManager.
Also, I doubt anything is Spring will call clear implicitly.
BUT Spring doesn't use one EntityManager per Thread but one per request.
So the next request in your web application will get a fresh EntityManager with a clear 1st level cache. So while the correct answer for the question you asked is "No, clear isn't called", the answer which is probably relevant is "Yes, the EntityManager is clear on each call of your controller method."

Using/configuring Spring Security with Spring 4 and Hibernate

I want to implement the login/logout (authentication/authorization) system of my Spring 4 MVC application with Spring Security.
Currently I use a very simple hand-made implementation which basically does nothing more than comparing the entered username and MD5 hashed password with the database values by looking up the user by the username using a custom service method and comparing the encrypted passwords.
If the passwords match, the username of the logged in member is saved in the session and a ControllerAdvice looks up the Member object for the user using the username in the session prior to each request. The checkLogin method returns true is username and password match:
#Service("loginService")
#Transactional
public class LoginServiceImpl implements LoginService {
private MemberDao dao;
//more methods
#Override
public boolean checkLogin(String username, String password) {
String hashedPassword = getPasswordHash(password);
return dao.checkLogin(username, hashedPassword);
}
}
This does work but is not a very elegant solution, does not handle different roles and is probably not very secure. Besides I want to become familiar with Spring Security.
Reading the official tutorial for Spring Security (http://docs.spring.io/spring-security/site/docs/4.0.4.RELEASE/reference/htmlsingle/#tech-userdetailsservice) the way to go to authenticate against the Login service method does not become clear to me.
The tutorial discusses authentication direct against the database but I cannot find anything about using a Service method to perform the authentication and in my layered architecture, the database is hidden behind the Servoce and Dao (Hibernate) layers.
Also most examples in the tutorial use XML based instead of Java based configuration which I use for my application.
After having search a lot with search engines, I still have not found a tutorial which implements Spring Security in a Spring MVC application using a familiar layered structure using a Service and Dao layer.
Do I need to bypass Service and DAO/Hibernate layers and authenticate directory against the database? Or write a custom authentication-provider implementing UserDetailsService as described in this post?
Spring Security 3 database authentication with Hibernate
And is configuring Spring Security possible with Java based configuration only? I am a bit lost with this issue so I hope for some hints...

Resources