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

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

Related

#Transactional in a service class with no call to database

When a service class has no implementation of Jpa repository ,My understanding is that it is wrong to annotate it with Transactional, for example this service class with should not have #Transactional
#Service
public class BillingAddressServiceImpl implements BillingAddressService {
public BillingAddress setByUserBilling(UserBilling userBilling, BillingAddress billingAddress) throws DataAccessException
{
billingAddress.setBillingAddressName(userBilling.getUserBillingName());
billingAddress.setBillingAddressStreet1(userBilling.getUserBillingStreet1());
billingAddress.setBillingAddressStreet2(userBilling.getUserBillingStreet2());
billingAddress.setBillingAddressCity(userBilling.getUserBillingCity());
billingAddress.setBillingAddressState(userBilling.getUserBillingState());
billingAddress.setBillingAddressCountry(userBilling.getUserBillingCountry());
billingAddress.setBillingAddressZipCode(userBilling.getUserBillingZipCode());
return billingAddress;
}
}
The Transactional annotation stands for declaring the database transaction handling of Spring bean methods.
Since your service method is not working with the database it makes no sense to declare a transaction handling.
Transactional annotations are only used with method or classes that makes calls to database,one of the uses of transactional annotation is rollback - which means when we make call to a database there would be a recording of the intermidiate state between the successful call and its original state, this is so that in the case of a failed call the system does not crash but is able to return to its original state

Spring managed transactions #Transactional annotation

Propagation setting is REQUIRED.
#Transactional(propagation = Propagation.REQUIRED)
Transaction is read/write.
In which scenario those are used? Please give me explain with example
Spring transaction default is
#Transactional(propagation = Propagation.REQUIRED)
So you do not need to specify the propagation property.
So, What does it mean by #Transactional annotation for a spring component ?
Spring framework will start a new transaction and executes all the method and finally commit the transaction.
But If no transaction is exists in the application context then spring container will start a new transaction.
If more than one method configured as Propagation.REQUIRED then transactional behavior assigned in a nested way to each method in logically but they are all under the same physical transaction.
So, What is the result ?
The result is if any nested transaction fail, then the whole transaction will fail and rolled back (do not insert any value in db) instead of commit.
Example:
#Service
public class ServiceA{
#Transactional(propagation = Propagation.REQUIRED)
public void foo(){
fooB();
}
#Transactional(propagation = Propagation.REQUIRED)
public void fooB(){
//some operation
}
}
Explanation :
In this example foo() method assigned a transactional behavior and inside foo() another method fooB() called which is also transactional.
Here the fooB() act as nested transaction in terms of foo(). If fooB() fails for any reason then foo() also failed to commit. Rather it roll back.
This annotation is just to help the Spring framework to manage your database transaction.
Lets say you have a service bean that writes to your database and you want to make sure that the writing is done within a transaction then you use
#Transactional(propagation = Propagation.REQUIRED)
Here is a small example of a Spring service bean.
#Service
class MyService {
#Transactional(propagation = Propagation.REQUIRED)
public void writeStuff() {
// write something to your database
}
}
The Transactional annotation tells Spring that:
This service method requires to be executed within a transaction.
If an exception gets thrown while executing the service method, Spring will rollback the transaction and no data is written to the database.

Hibernate Filters with JPA EntityManagerFactory and 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();

Service layer and dao layer in java ee EJBs

Question: Can anyone, in context to Java EE and EJBs, show a specific DAO class (or more than one) that has two different methods. and a service class that calls those 2 methods in ONE transactional boundary with roll back?
I have an EJB but I want to use it as service layer like in spring #Transactional methods.
1) is it a good idea ?
2) how can I make many dao method calls in one "transaction" in one method? I think I have to make some strategy on transaction.begin() and . comit()? can anyone show a code example please?
Some of the main advantages would be that:
a- all the small immutable DAO transactions will be committed in "one go" in the single database connection made (in single transactional boundries)
b- If say I have 4 dao calls in server and the third one fails, since its one transactional boundry, I can do roll backs.
c- my immutable DAO methods will be re-usable in many other places.
Java EE example:
import com.....entities.Users;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
#Stateless
public class UsersBean {
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
public Users sayHello() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("CommunityPU");
EntityManager em = emf.createEntityManager();
Users user = em.find(Users.class, 1);
em.close();
emf.close();
return user;
}
}
vs. spring:
#Controller
class MyControllerClass {
#RequestMapping...
method(){
ServiceCall()...
//put something to modelAndView object here and redirect to jsp page.
return "home"; // this will redirect data to home.jsp
}
}
//Service class /////////
#Service
class MyServiceClass{
#Transactional
SomeServiceMethod(){
DaoMethod();
SomeMoreDaoMethods();
}
}
//Dao class ////////
#Autowired
EntityManager em;
#Repository
class MyDaoClass{
DaoMethdon(){em.find(...)}
}
/view/myjsps.jsp path to view directory set in spring.xml
Edit - 1 (cross question to the answer for further clarification)
1) will the DAO itself be an EJB? or EJBs are strict service layers that call other immutable dao methods (that reside in dao classes).
2) we wont use entitymanager in EJBs but in Daos. correct?
3) how about using #Transactional (Until Java EE 7 only EJB where transactional and the #Transactional annotation didn't exist.) or #TransactionAttribute.
4) what if we use non #stateless. Then it wont manage the daos in one transactional boundry not use roll backs?
RND links:
https://stackoverflow.com/a/17840851
http://docs.oracle.com/javaee/5/tutorial/doc/bncij.html
Is is a good idea?
Yes. That's what EJBs are for, basically.
how can I make many dao method calls in one "transaction" in one method?
You just do it:
#Stateless
public class MyService {
#Inject
private FirstDao firstDao;
#Inject
private SecondDao secondDao;
// stateless EJBs are transactional by defaults.
public void doStuff() {
firstDao.doSomething();
secondDao.doSomethingElse();
}
}
EJBs are transactional by default. You don't need to start and commit transactions programmatically. The container does that for you: if any of the 2 DAO calls throws a runtime exception, the transaction will roll back. Otherwise, it will commit.
Also note that the entity manager shouldn't be used by your service EJB. That's what DAOs are for: deal with persistence. So the DAOs should be the one using the entity manager:
public class FirstDao {
#PersistenceContext
private EntityManager em;
...
}
Regarding your last questions:
DAOs can be EJBs themselves, but it's not necessary, since transactions are normally demarcated by the service layer.
I already answered that. Of course The Data access objects are the ones who must use the EntityManager, since their job is to handle persistence, and the EntityManager is used to access the database.
Do it the way you want. What's important is that your services should be transactional, whatever the way you make them transactional. Transactional was introduced to remove the need for EJBs and have transactional CDI beans. If you prefer it that way, then fine.
Small note: an immutable method doesn't make sense. Something (like an object) is immutable when its state never changes. Methods don't have state.

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.

Resources