I'm learning about how to create REST API with JPA and Hibernate and a MySQL database and I see this #Transactional annotation. Can someone explain what is the use of this annotation?
For example I have this simple DAO class:
#Repository
public class EmployeeDAOHibernateImpl implements EmployeeDAO {
// define field for entitymanager
private EntityManager entityManager;
// set up constructor injection
#Autowired
public EmployeeDAOHibernateImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
#Transactional
public List<Employee> findAll() {
// get the current hibernate session
Session currentSession = entityManager.unwrap(Session.class);
// create a query
Query<Employee> theQuery =
currentSession.createQuery("from Employee", Employee.class);
// execute query and get result list
List<Employee> employees = theQuery.getResultList();
// return the results
return employees;
}
}
You can see the #Transactional used for findAll() method, but if I delete this #Transactional I get the same output... then what is the use of this #Transactional?
#Transactional annotation is used when you want the certain method/class(=all methods inside) to be executed in a transaction.
Let's assume user A wants to transfer 100$ to user B. What happens is:
We decrease A's account by 100$
We add 100$ to B's account
Let's assume the exception is thrown after succeeding 1) and before executing 2). Now we would have some kind of inconsistency because A lost 100$ while B got nothing.
Transactions means all or nothing. If there is an exception thrown somewhere in the method, changes are not persisted in the database. Something called rollback happens.
If you don't specify #Transactional, each DB call will be in a different transaction.
Generally the #Transactional annotation is written at the service level.
It is used to combine more than one writes on a database as a single atomic operation.
When somebody call the method annotated with #Transactional all or none of the writes on the database is executed.
In the case of read operations it is not useful and so it is in case of a single atomic write. You are using it in a single read (select) so adding or removing the #Transactional annotation has no impact.
The class declares #Transactional on itself or its members, Spring creates a proxy that implements the same interface(s) as the class you’re annotating. In other words, Spring wraps the bean in the proxy and the bean itself has no knowledge of it.
A proxy provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied.
Internally, its the same as using a transaction advice (using AOP), where a proxy is created first and is invoked before/after the target bean’s method.
The generated proxy object is supplied with a TransactionInterceptor, which is created by Spring. So when the #Transactional method is called from client code, the TransactionInterceptor gets invoked first from the proxy object, which begins the transaction and eventually invokes the method on the target bean. When the invocation finishes, the TransactionInterceptor commits/rolls back the transaction accordingly
Related
I am having a problem with Spring JPA Data and nested transactions. Following are two methods with a nested transaction of my service.
#Service
public UserService {
#Transactional
public User createUser(UserDto userDto) {
....
user = saveUser(user);
sendEmail(user);
....
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public User saveUser(User user) {
return userRepository.save(user);
}
It happens there is one scenario that the method userRepository.save() should throw an exception but somehow is not being thrown, it looks like it is waiting the parent transaction to be finished. I was expecting the exception being thrown on the saveUser method and the sendEmail method not even to be executed.
Because the method UserService.saveUser have the propagation set to Propagation.REQUIRES_NEW I was expecting that transaction to be commited (the SQL statement to be executed) and any exception being propagated.
I did not setup anything related with Transaction, so i believe that the flush mode is set to AUTO.
Can anyone spot what i am doing wrong or what is my misconception?
It's because you're invoking #Transactional method from within same bean.
#Transactional only works on methods invoked on proxies created by spring. It means, that when you create a #Service or other bean, method called from the outside will be transactional. If invoked from within bean, nothing will happen, as it doesn't pass through proxy object.
The easiest solution would be to move the method to another #Service or bean. If you really want to keep it within same component, then you need to invoke it, so that it gets wrapped in proxy by spring AOP. You can do this like that:
private YourClass self;
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void postContruct(){
self = applicationContext.getBean(YourClass.class);
}
Then invoking method on self would result in opening a transaction.
In other words: you are not experiencing any of those anomalies, because #Transactional over saveUser does not work.
What is the difference between using #Transactional in dao layer and in service layer?
#Transactional
class UserDAO{}
or
#Transactional
class UserService{}
We can put this annotation in both the layers. So what is the difference?
if you add #Transactional annotation at Service layer and you are performing multiple operations on database, then all these operations will be in a single transaction and with that you can make sure that both the operations are commited, if any of them failed then roll back.
For example: There is a case you want to create an Employee and your business rule says that for every Employee you create, you need to create User in your database. In such case we would use Transactional annotation at service layer
#Service
public class EmployeeService {
....
#Transactional
public int createEmployee(Employee emp) {
//create Employee
employeeDao.createEmployee(emp);
User user = new User();
// some fileds of employee are used to create a User
user.setEmployeeId(emp.getEmployeeId());
....
userDao.createUser(user);
...
}
}
There is no difference at all. But best practice is use it in Service layer. Cause sometimes you need to make transaction through more than one entity. So if you declare transactions in your dao manually. And you call method from service with two methods from your daos you will have two transactions in one call. And that is something what you don't want.
Does Spring issue a commit to the database after each package call, or does it only commit after everything is done?
I am using Spring and Struts. In my controller class, I am calling many database packages with spring stored procedure in a DAO class. each call has its only method in the DAO class
My question is, will Spring commit only after all calls have been made from the controller class and the controller has finished, or will it commit after each execution of a SpringStoredProcedure?
my_package_getusers = SpringStoredProcedure.getStoredProcedureCompiled(getJdbcTemplate()
....
my_package_getusers.execute(params).get("result")
Spring utility classes from spring-jdbc don't make any commits. The responsibility for commiting transaction belongs to the spring-tx (transaction support.
This is usually made by placing #Transactional annotation on the method that should be run in transaction scope. So if you have method
#Transactional
public void doSomething(SomeClass arg) {...}
entering that method will create new transaction, and that transaction will be commited after leaving the transaction, if the transactional context doesn't exist. However, if that method is called from other method annotated with #Transactional, the parent transaction context will be used.
As alternative, you can use org.springframework.transaction.support.TransactionTemplate to gain more control over transactions (for example, launching separate transaction from transactional context).
Example:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// do something in trancation)
}
});
Note, that on some databases, such as Oracle, you can commit transaction within stored procedure, which will persist all changes made in existing transaction, and the new transaction will follow.
I'm using a JPA EntityListener to do some additional audit work and am injecting a Spring-managed AuditService into my AuditEntryListener using #Configurable. The AuditService generates a collection of AuditEntry objects. The AuditService is itself a Singleton scoped bean, and I'd like to gather all the AuditEntry objects under a common key that can then be accessed by the outermost service layer (the one that invoked the persist call which in turn triggered the EntityListener).
I'm looking at using Spring's TransactionSynchronizationManager to set a specific transaction name (using UID() or some other unique strategy) at the beginning of the transaction, and then using that name as a key within the AuditService that will allow me to group all AuditEntry objects created within that transaction.
Is mixing declarative and programmatic transaction management have the potential for trouble? (Though I'm doing nothing more than setting the transaction name). Is there a better way to associate the generated AuditEntry objects with the current transaction? This solution does work for me, but given that the TransactionSynchronizationManager isn't intended for application use, I'd like to make sure that my use of it won't cause some unforseen problems.
Related Question
Finally, a related, but not immediately pertinent question: I know that the documentation for JPA EntityListeners cautions against using the current EntityManager, but if I did want to use it to diff an object against it's persisted self, would I be safe using an #Transactional(propagation=REQUIRES_NEW) annotation around my preUpdate() method?
Prototype Code:
Service Class
#Transactional
public void create(MyEntity e) {
TransactionSynchronizationManager.setCurrentTransactionName(new UID().toString());
this.em.persist(e);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
Set<AuditEntry> entries = auditService.getAuditEntries(TransactionSynchronizationManager.getCurrentTransactionName());
if(entries != null) {
for(AuditEntry entry : entries) {
//do some stuff....
LOG.info(entry.toString());
}
}
}
});
}
JPA EntityListener
#Configurable
public class AuditEntryListener {
#Autowired
private AuditService service;
#PreUpdate
public void preUpdate(Object entity) {
service.auditUpdate(TransactionSynchronizationManager.getCurrentTransactionName(), entity);
}
public void setService(AuditService service) {
this.service = service;
}
public AuditService getService() {
return service;
}
}
AuditService
#Service
public class AuditService {
private Map<String, Set<AuditEntry>> auditEntryMap = new HashMap<String, Set<AuditEntry>>();
public void auditUpdate(String key, Object entity) {
// do some audit work
// add audit entries to map
this.auditEntryMap.get(key).add(ae);
}
}
#Filip
As far as I understand, your requirement is:
Have an unique token generated within each transaction (database
transaction of course)
Keep this unique token easily accessible across all layers
So naturally you're thinking about the TransactionSynchronizationManager provided by Spring as a facility to store the unique token (in this case, an UID)
Be very carefull with this approach, the TransactionSynchronizationManager is the main storage helper to manage all the #Transactional processing for Spring. Under the #Transactional hood, Spring is creating an appropriate EntityManager, an appropriate Synchronization object and attach them to a thread local using TransactionSynchronizationManager.
In your service class code, inside a #Transactional method your are tampering with the Synchronization object, it can end up with undesirable behavior.
I've done an indept analysis of how #Transactional works here, have a look: http://doanduyhai.wordpress.com/2011/11/20/spring-transactional-explained/
Now back to your needs. What you can do is:
Add a Thread local to the AuditService, containing the unique token when entering the #Transactional method and destroy it when exiting the method. Within this method call, you can access the unique token in any layer. Explanation for ThreadLocal usage can be found here: http://doanduyhai.wordpress.com/2011/12/04/threadlocal-explained/
Create a new annotation, let's say #Auditable(uid="AuditScenario1") to annotate methods that need to be audited and use Spring AOP to intercept these method calls and manage the Thread local processing for you
Example:
Modified AuditService
#Service
public class AuditService {
public uidThreadLocal = new ThreadLocal<String>();
...
...
}
Auditable annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#Documented
public #interface Auditable
{
String uid();
}
Usage of #Auditable annotation
#Auditable(uid="AuditScenario1")
#Transactional
public void myMethod()
{
// Something
}
Spring AOP part
#Around("execution(public * *(..)) && #annotation(auditableAnnotation))
public Object manageAuditToken(ProceedingJoinPoint jp, Auditable auditableAnnotation)
{
...
...
AuditService.uidThreadLocal.set(auditableAnnotation.uid())...
...
}
Hope this will help.
You can come up with a solution using the TransactionSynchronizationManager. We register a "TransactionInterceptorEntityListener" with JPA as an entity-listener. What we wanted to achieve is the ability to listen to CRUD events such that we can work with a spring managed "listener" that has a lifecycle tied to the current transaction (i.e., spring-managed but instance per transaction). We sub-class the JPATransactionManager and introduce in the prepareSynchronization() method, a hook to setup a "TransactionInterceptorSynchronizer." We also use the same hook for allow code (in programmatic tx) to associate and retrieve arbitrary objects with the current transaction and also register jobs that run before/after transaction commit.
The overall code is complex, but definitely do-able. If you use JPATemplates for programmatic tx, it is tough to achieve this. So we rolled our own template that simply calls the JPA template after taking care of the interceptor work. We plan to open-source our JPA library (written on top of Spring's classes) soon.
You can see a pattern of adding custom transactions and hooks with Spring managed transactions in the following library for Postgresql
I've seen a method in a Service class that was marked as #Transactional, but it was also calling some other methods in that same class which were not marked as #Transactional.
Does it mean that the call to separate methods are causing the application to open separate connections to DB or suspend the parent transaction, etc?
What's the default behavior for a method without any annotations which is called by another method with #Transactional annotation?
When you call a method without #Transactional within a transaction block, the parent transaction will continue to the new method. It will use the same connection from the parent method (with #Transactional) and any exception caused in the called method (without #Transactional) will cause the transaction to rollback as configured in the transaction definition.
If you call a method with a #Transactional annotation from a method with #Transactional belonging to the same Spring Bean, then the called methods transactional behavior will not have any impact on the transaction. But if you call a method with a transaction definition from another method with a transaction definition, and they belong to different Spring Beans, then the code in the called method will follow its own transaction definitions.
You can find more details in the section Declarative transaction management of spring transaction documentation.
Spring declarative transaction model uses AOP proxy, so the AOP proxy is responsible for transactions creation. The AOP proxy will be active only if the called method belong to a different Spring Bean than the caller one.
Does that mean the call to separate methods are causing the application to open separate connections to DB or suspend the parent transaction, etc?
That depends on a propagation level. Here are all the possible level values.
For example in case a propagation level is NESTED a current transaction will "suspend" and a new transaction will be created ( note: actual creation of a nested transaction will only work on specific transaction managers )
What's the default behavior for a method without any annotations that is called by another method with #Transactional annotation?
The default propagation level ( what you call "behavior" ) is REQUIRED. In case an "inner" method is called that has a #Transactional annotation on it ( or transacted declaratively via XML ), it will execute within the same transaction, e.g. "nothing new" is created.
#Transactional marks the transaction boundary (begin/end) but the transaction itself is bound to the thread. Once a transaction starts it propagates across method calls until the original method returns and the transaction commits/rolls back.
If another method is called that has a #Transactional annotation then the propagation depends on the propagation attribute of that annotation.
The inner method will affect the outer method if the inner method is not annotated with #Transactional.
In case inner method is also annotated with #Transactional with REQUIRES_NEW, following will happen.
...
#Autowired
private TestDAO testDAO;
#Autowired
private SomeBean someBean;
#Override
#Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
testDAO.insertUser(user);
try{
someBean.innerMethod();
} catch(RuntimeException e){
// handle exception
}
}
#Override
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
throw new RuntimeException("Rollback this transaction!");
}
The inner method is annotated with REQUIRES_NEW and throws a RuntimeException so it will set its transaction to rollback but WILL NOT EFFECT the outer transaction. The outer transaction is PAUSED when the inner transaction starts and then RESUMES AFTER the inner transaction is concluded. They run independently of each other so the outer transaction MAY commit successfully.