I've got situation like this:
#Transactional
#Override
public void register(String username, UserPasswordNew userPasswordNew, UserAccount userAccount) throws UserNameAlreadyExistsException {
.....
entityManager.merge(userAccountToSave);
}
I made some research but check me if I understand well. I've got entityManager (transaction scope). Method register is #Transactional so it means that this method is wrapped in proxy. When persistence context is created ? During the first call of entityManager.merge () ?? Transaction is commit after method because it's wrapped in proxy. So persistence context is removed after commit ?
Correct me if I am wrong, but you are using transaction scoped entitymanager, so during each call to entitymanager it ensure that persistence context exists, here entitymanager creates a new one and uses it to merge - and,as in transaction-scoped entitymanager, persistence context will be removed after each commit.
Related
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.
In this example, I don't know how to do rollback the transaction if a condition is verified. This is a Spring MVC application with JPA + Hibernate for persistence
In CartController:
#RequestMapping(value="/buy",method=RequestMethod.POST)
public String buy(){
CartDAO.buy();
return "redirect:/";
}//buy
In CartDAOImpl
#Transactional
public class CartDAOImpl implements CartDAO {
#PersistenceContext
private EntityManager em;
public void buy(){
....
if(x !=y) throw new MyException();
em.persist(Item);
....
}
}
In applicationContext-servlet.xml
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
What's the best solution to this problem? Sorry for my English
From Spring documentation about rolling back declarative transactions:
In its default configuration, the Spring Frameworkâs transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.
You can configure exactly which Exception types mark a transaction for rollback, including checked exceptions. The following XML snippet demonstrates how you configure rollback for a checked, application-specific Exception type.
Source: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-rolling-back
You can declare in the #Transactional that you want Spring to performa a rollback when your MyException is thrown:
#Transactional(rollbackFor=MyException.class)
I'm having problems whilst trying to test a JPA entity lifecycle observer, registered as POST_COMMIT_INSERT
Because my observer is a spring bean, I wire it into the entity manager as follows:
private void configureHibernateHooks(HistoricEventListener<?> listener) {
SessionFactory sessionFactory = getSessionFactory();
EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
EventListenerRegistry.class);
if (listener instanceof PostInsertEventListener)
{
registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener((PostInsertEventListener) listener);
}
}
SessionFactory getSessionFactory() {
Session session = (Session) entityManager.getDelegate();
SessionFactory sessionFactory = session.getSessionFactory();
return sessionFactory;
}
My test is annotated as #Transactional. Therefore, as I understand it, each test runs within it's own transaction. This is preventing my observer method from being invoked, as the transaction doesn't commit during my test, so the POST_COMMIT_XXX listeners are never observed.
I've tried injecting the EntityManager and manually commiting transactions, but that resulted in exceptions.
What's an appropriate strategy for testing these?
You can use the #Rollback(false) annotation on a test method to direct spring to commit the transaction instead of rolling it back.
Even triggering an entityManger.flush() should suffice. I don't think the event triggering is associated with the commit of the transaction (the name might be misleading).
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.
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