Spring: how to rollback declarative transaction - spring

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)

Related

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.

Spring transaction and PersistenceContext

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.

Spring transactional dont rollback when exception is mapped by ExceptionMapper

I have a RESTFul service (implemented by jersey) . The service is marked with #Transactional.
I declared an ExceptionMapper like this:
#Provider
public class ThrowableMapper implements ExceptionMapper<Throwable> {
private static final Logger log = Logger.getLogger(ThrowableMapper.class);
public Response toResponse(Throwable ex) {
log.error("throwable", ex);
return Response.status(500).entity("Internal Error").type("text/plain").build();
}
}
when exceptionmapper is not declared than transaction is rollback.
However, when i have an ExceptionMapper transaction is commit without rollback.
I assume the reason for for transaction not being rollback is because when exception is caught by ExceptionMapper than spring transaction proxy dosnt detect that exception was thrown ,so transaction is not rollback.
Is there a way to overcome this?
This is not the cleanest solution, but didn't find anything else.
I add this to the ExceptionMapper:
TransactionAspectSupport.currentTransactionStatus( ).setRollbackOnly();

How to test hibernate lifecycle observers?

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).

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