Hibernate Filters with JPA EntityManagerFactory and Spring - spring

I have a jersey + spring application that is using EntityManagerFactory and spring JpaTransactionManager to handle the db manipulations. The JPA implementation is hibernate.
I would like to know is there a way to enable hibernate filters in this scenario.
I tried extending org.springframework.orm.jpa.JpaTransactionManager and overriding
#Override
protected EntityManager createEntityManagerForTransaction() {
EntityManager manager = super.createEntityManagerForTransaction();
Session session = manager.unwrap(Session.class);
return manager;
}
But I am not sure that this method is called at the right place.
EDIT:
I am using spring JpaRepositories to persist/query entities.

I found an answer for this problem. It seems like other people are still struggling with this, I will post my solution.
I am enabling the filters that I need in business service methods that are marked as #Transactional (that is important).
In your service, inject the entity manager factory:
#Autowired
private EntityManagerFactory entityManagerFactory;
Inside the #Transactional method obtain the entity manager from the transactionManager, unwrap it to hibernate session and enable the filters that you need. This is done as follows:
//Obtain the entity manager for the current transaction
EntityManagerHolder holder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(entityManagerFactory);
EntityManager entityManager = holder.getEntityManager();
//Unwrap to get the underlying hibernate session
Session hibernateSession = entityManager.unwrap(Session.class);
//Configure your filters
Filter publishedAfterFilter = hibernateSession.enableFilter("...");
publishedAfterFilter.setParameter("...", ...);
publishedAfterFilter.validate();

Related

Getting hibernate session on a shared entity manager proxy gives back the same proxy

In our Spring Boot 1.5 project, we were using Spring ORM 5.3.3, Hibernate 5.0.12
To get the session, we had this utility class that uses entity manager to get the current session
The entity manager that gets injected here is Shared Entity Manager Proxy
#Component
public class EntityListenerUtil {
#PersistenceContext
private EntityManager entityManager;
public EntityListenerUtil() {
}
public EntityManager getCurrentEntityManager() {
return this.entityManager;
}
public Transaction getCurrentTransaction() {
Session session = this.getCurrentSession();
return session.getTransaction();
}
public Session getCurrentSession() {
return getCurrentEntityManager().unwrap(Session.class);
}
}
When we started using spring boot 2.4.2, it pulled in the same Spring ORM 5.3.3 and Hibernate 5.4.27
The same code when ran now gives back the same shared entity manager proxy bean the entityManager field contains instead of giving the session implementation (SessionImpl for example)
The difference is that hibernate 5.0.12 Session does not extend EntityManager but 5.4.27 Session does.
The use of EntityManager shouldn't alter the behavior of fetching Session with the unwrap method with hibernate version change.
Spring ORM SharedEntityManagerCreator checks if the type we want to unwrap is an instance of the same proxy and if so, it returns back the same proxy. That condition was returning false before as Hibernate 5.0.12 Session didn't extend EntityManager but the new one does.
Any suggestions on how to get around this?

Spring autowiring with bean scope of prototype

I have a question in spring with autowire with a bean which is having a scope of prototype..
So basically i am writing a code which is spring with JPA.So i am autowiring my entity manager in my DAO layer .I am loading the entitymanager from a class by using the #configuraion Annotation .
#Configuration
public class DALConfigurationLoader {
#Bean
#Scope("prototype")
public EntityManager getEntityManager() {
}
When i do this i am expecting that for every request it should get a new bean .
#Component
public class OfferPriceDomainDAOImpl {
#Autowired
private EntityManager entityManager;
public OfferPrice getOfferPrice(String offer_Price_Id) throws DataAccessException{
//use entitymanager here
}
}
In this case it is a single entity manager for all the request which is wrong.i want each method should get a new entity manager .As based on the jpa specification every new request should process a new entity manager...How can i autowire a bean with a scope of prototype..
I would really appreciate if some one can answer my question..
Thank,
Swati
Use #PersistenceContext to inject an EntityManager, not #Autowired, as outlined in the JPA section of the Spring reference guide. It takes care of the lifecycle for you properly.
As to why it wasn't working the way you thought it might: whenever an instance of your DAO is created, it would be injected with an EntityManager. Since the EntityManager is scope=prototype, a new one will be created for each DAO that needs to be injected for one. However, since your DAO is a singleton, only one of them is created, so only one EntityManager is ever needed.
#Inject // or #Autowire
Provider<EntityManager> entityManagerProvider;
and then get EntityManager instance using entityManagerProvider.get().
I used javax.inject.Inject instead of Autowire because Provider is defined there too. Also that also would work in Guice.

JPA's EntityManager or Hibernate's HibernateTemplate with Spring

I have decided to use Spring, Hibernate, and Restlet to create a web service. I am new to all of these three technologies. My question is this: How do I decide whether to use JPA's EntityManager or Hibernate's HibernateTemplate?
Code snippet for JPA's EntityManager:
protected EntityManager entityManager;
#PersistenceContext
public void setEngityManager(EntityManager entityManger) {
this.entityManager = entityManager;
}
Code snippet for Hibernate's HibernateTemplate:
private SessionFactory sessionFactory;
private HibernateTemplate hibernateTemplate;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
If you are someone who like interface-based-implementation, then JPA is the interface definition and Hibernate is one of the implementations. We decided to use JPA semantics in our project (with a very long term plan to replace Hibernate with something similar and light-weight probably).
If you want to stick to hibernate in future, then no point in using EntityManagerFactory, you can go ahead and use SessionFactory. And just inject definition for this using java based configuration or xml. It must be available in application context.
But in future if you might want to move to different jpa provider, like toplink etc, then you should use EntityManagerFactory as it allows you to have implementation from various provider. Because providers implement jpa specification. So in future you just need to have different configuration in your application context and you should be able to use that.

How to use transaction-scoped persistence context for non-transactional reading query?

I read the Spring doc and it says:
The #PersistenceContext annotation has an optional attribute type, which defaults to
PersistenceContextType.TRANSACTION. This default is what you need to receive a shared
EntityManager proxy.
Does this mean I have to make EntityManager work in a transaction?
How does it work for non-transactional method (reading query), such as the loadProductsByCategory in the below code?
What does the "shared" mean? How can it use EntityManager sharing with others?
Do I need to add #Transactional to the method loadProductsByCategory in order to bind the EntityManager to the thread? Because the class ProductDaoImpl is singleton and works in multi-thread, but entityManager is not thread-safe.
#Service
public class ProductDaoImpl implements ProductDao {
#PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
#Transactional
public void loadProductsByCategory(Product product) {
em.persist(product);
}
}
There is a detailed analysis of this behavior at the following blog link. http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/ Here is my summary of it.
EntityManager is a java interface which allows spring to provide it's own implementation of the interface. The implementation injected by spring use a dynamic proxy to handle the calls to the entity manager. The dynamic proxy behaves the following way.
if there is no #Transactional annotation as in loadProductsByCategory spring will create an instance of the EntityManager em when em.createQuery is called, spring will not return the Query object created by JPA but it will return Spring Proxy of EntityManager this spring proxy forwards all calls to the real implementation of Query and it waits until the getResult or getSingleResult or executeUpdate are called and it immediately closes the Entity Manager.
So when there is no #Transactional Spring will make sure that the entity manager is closed as soon as possible, i.e. after each method call on the entity manager or after a result set is extracted. In your above example if you comment out the query.getResultList() you will end up leaking an entity manager instance that does not get closed
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
return null;
// a leak of an entity manager will happen because getResultList() was never called, so
// spring had no chance to close the entity manager it created when em.creaueQuery was
// invoked.
// return query.getResultList();
}
When there is #Transactional attribute the spring transaction manager will create a transactional context before the transactional method is called. When transactional method calls any method on the entity manager Spring will create a brand new EntityManager instance and associate it with current transnational, if the transactional method, calls another method, which calls another and all those methods use an entity manager then the entity manager is shared across all those calls. here is an example.
main(..)
{
Foo foo = call spring to get foo instance
foo.doFoo();
}
public class Foo {
#PersistenceContext
EntityManager em;
#Autowired
Bar bar;
#Transactional
public doFoo(){
// before this method is called spring starts a spring transaction
em.createQuery(....) // here spring will create an instance of the Entity manager
// and assoicated with the current tx
bar.doBar(); // call bar transactional method
}
}
public calss Bar {
#PersistenceContext
EntityManager em;
#Transactional
public doBar(){
// no tx is started here because one was already started in doFoo
em.createQuery(....) // spring looks under the current tx and finds that it has
// an entity manager, was created in the doFoo() method so this entity manager
// is used, This is what is meant by sharing of the entity manager.
}
}
To answer your last last question.
Do I need to add #Transactional to the method loadProductsByCategory in order to bind the EntityManager to the thread? Because the class ProductDaoImpl is singleton and works in multi-thread, but entityManager is not thread-safe.
The #Transactional causes spring to bind a spring tx to the current thread, and then the entity manager is bound to the spring tx which is bound via thread local to the current thread.
Pro JPA 2 book has a decent explanation of this stuff in chapter 6, it is bit dense and it is explained in the context of Java EE but the steps are the same for spring.

Spring JPA : Application managed persistence context with #Transactional and #PersistenceContext

Currently im trying out the application managed persistence context, by creating the entity manager manually and store them to enable transaction that spans multiple request calls (perhaps something like extended persistence context) in JSE application.
But, im wondering whether i can avoid sending the entityManager object throughout the service and DAO methods as an additional parameter by making use of the spring's #PersistenceContext injection and mark the methods with #Transactional annotation to use the transaction started manually with that entity manager.
I think i can somehow manage this by using a ThreadLocal for this feature, but i'll be happier to be able to attach this to the spring framework.
This is an example of What i have in mind :
The UI action method :
Here we can see the transaction is started by the ui logic, since there iss no facade / command method in the backend to group these callings to the business logic :
Long transactionid = tool.beginTransaction();
// calling business methods
tool.callBusinessLogic("purchase", "receiveGoods",
paramObject1, transactionid);
tool.callBusinessLogic("inventory", "updateInventory",
paramObject2, transactionid);
tool.commitTransaction(transactionid);
Inside the tool :
public Long beginTransaction() {
// create the entity --> for the #PersistentContext
Entitymanager entityManager = createEntityManagerFromFactory();
long id = System.currentTimeMillis();
entityManagerMap.put(id, entitymanager);
// start the transaction --> for the #Transactional ?
entityManager.getTransaction().begin();
return id;
}
public void commitTransaction(Long transactionId) {
EntityManager entityManager = entityManagerMap.get(transactionId);
entityManager.getTransaction().commit();
}
public Object callBusinessLogic(String module, String function,
Object paramObject, Long transactionid) {
EntityManager em = entityManagerMap.get(transactionId);
// =================================
// HOW TO DO THIS????
// =================================
putEntityManagerIntoCurrentPersistenceContext(em);
return executeBusinessLogic(module, function, paramObject, transactionid);
}
And the example for the service method :
public class Inventory {
// How can i get the entityManager that's been created by the tool for this thread ?
#PersistenceContext
private EntityManager entityManager;
// How can i use the transaction with that transactionId ?
#Transactional
public void receiveGoods(Param param) {
// ........
}
}
Is there anyway to achieve this ?
Thank you !
Spring's handling of the #PersistenceContext annotation does almost exactly what you're after, with one big difference: you always get a transaction scoped EntityManager and Spring injects always the same instance for the same thread, so you have kind of propagation and don't have to worry about thread-safety. But you'll never get an extended context this way!
Believe me, Spring 3 and extended persistence context don't play well together, maybe this will change in Spring 3.1 but I'm afraid that's not in their focus. If you want to use an extended persistence context let Spring inject the EntityManagerFactory (via #PersistenceUnit annotation) and then create the EntityManager on your own. For propagation you'll have to either pass the instance as a parameter or store it in a ThreadLocal yourself.
Indeed to have a application managed persistence context, you need to somehow "hack" the #Transactional & #PersistenceContext infrastructure by providing them your own Entity Manager and do not let Spring create its own.
The key to achieve this is to play a little bit with the TransactionSynchronizationManager class to register your own Entity Manager to the thread local, Spring will use it to inject to the #PersistenceContext attribute.
I had this need some time ago for my own application and I've designed a small architecture based on Spring AOP to manage the extended persistence context.
Details here: JPA/Hibernate Global Conversation with Spring AOP
When you configure your transactions via #Transactional, then you should handover the configuration of your transactions to the annotation.
Here you start your transaction and then hope that the #Transactional will also be triggerd.
for more information you would best start reading http://static.springsource.org/spring/docs/2.5.x/reference/transaction.html => 9.5.6. Using #Transactional

Resources