Spring Transactional Annotation
Asked Answered
U

2

8

I'm trying to get a better handle on the use of Spring's @Transactional attribute. I understand that it basically wraps the contents of the method marked as @Transactional in a transaction. Would it be appropriate to mark a service/business layer method as transactional, as opposed to the actual DAO method, as I have done here?

Service Implementation

public class UserServiceImpl implements UserServiceInt{
   @Autowired
   private UserServiceDAO serviceDAO;


   @Override
   public User getUser(int id){
      return serviceDAO.getUser(id);
   }

   @Override
   @Transactional
   public void updateUserFirstName(int id, String firstName) throws SomeException{
      User userToUpdate = getUser(id);
      if(userToUpdate == null){
         throw new SomeException("User does not exist");
      }
      userToUpdate.setFirstName(firstName);
      serviceDAO.updateUser(userToUpdate);
   }

}

DAO Implementation

public class UserServiceDAOImpl implements UserServiceDAOInt{
   @PersistenceContext(unitName="myUnit")
   private EntityManager entityManager;

   @Override
   public void updateUser(User user){
      entityManager.merge(user);
   }

}

I'm not even sure if the call to merge is even necessary. How does Spring know which EntityManager to use since there isn't an EntityManager declare in the UserServiceImpl class?

Umbrageous answered 5/6, 2015 at 13:36 Comment(3)
Yes it's appropriate to annotate you service or service methods as @Transactional - for example in case the service spans more than a single DAO. Also, you are right, you don't have to explicitly call merge. The User object is already associated with the persistence context (by calling get()) and it's state synchronized with the DB at the end of the transaction . Merge is used to update an object which had been changed outside of a transactionSussi
a bit of topic for your question, but you might find it relevant, take a look at projects.spring.io/spring-data-jpa it will remove a lot of boilerplate code from your DAO layerPostmistress
Check my answer here, maybe it will help u #30491424Larynx
A
6

We mark a Service layer with @Transactional when a method in a Service class is having multiple database calls and we want either all calls should happen or no one should happen or we can say if any call fail then whole transaction should rollback. If we are not falling under this criteria then we can opt for @Transactional on DAO layer also.

How does Spring know which EntityManager to use since there isn't an EntityManager declare in the UserServiceImpl class?

Spring is referring the EntityManager from persistence.xml(from classpath), whose structure is similar to below:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
    <persistence-unit name="myUnit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:/YourDatasource</jta-data-source>

        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>
</persistence>
Arsyvarsy answered 5/6, 2015 at 13:58 Comment(0)
C
0

First it is important to see, that there are 2 different @Transactional methods in Spring: The JakartaEE standardized:

import jakarta.transaction.Transactional;

The Spring proprietary:

import org.springframework.transaction.annotation.Transactional;

Both work, latter one gives you more options. @Transactional is handled by a proxy that is at runtime intercepting all calls to your component. Spring saves the Transaction context in ThreadLocal variables this is how Spring determines to which transaction a call (thread) belongs to. If you do not mess things up with self created threads, everything will be fine.

Answering your question: if you have only your repositories @Transactional (which the Spring Jpa Repositories automatically do) each call to a repository will run in its own transaction.

This article describe quite well how things work: https://ciit-training.com/2024/01/06/transactional-in-spring-how-it-works/

Cockeye answered 6/1 at 16:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.