Where should we use @Transactional and where is the service level?

I have a rest style controller in Spring. In the controller, I have introduced dao interfaces. From the controller, I save the data. In other words, I have a REST web service. people send me data and I tolerate it.

/**
 * Payment rest controller which receives 
 * JSON of data
 */
@Controller
@RequestMapping("/data")
public class PaymentTransaction {

    @Autowired
    private TestDao dao;

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    @ResponseBody()
    public String test(HttpServletRequest request) {

    ...

    }

      

At the moment I have @transaction annotation in Dao classes. For example:

    import org.springframework.transaction.annotation.Transactional;
    @Component
    @Transactional
    public interface TestDao {

        @Transactional(propagation = Propagation.REQUIRED)
        public void first();

    }

      

I read that this is very bad style. Using this answer on stackoverflow, here is an explanation and examples why this is bad - we shouldn't add this annotation to the DAO and to the controller either. We have to add it to the service layer.

But I don't understand what is the service layer? Or where is it? I have nothing like this. where should i write @Transactional annotation?

Respectfully,

+3


source to share


2 answers


According to the quoted post, you should create your classes one way or another (rather pseudocode):

  • controller (responsible for handling client requests and responses)

    @Controller
    @RequestMapping("/data")
    public class TestREST {
        @Autowired
        private TestService service;
    
        public void storePayment(PaymentDTO dto) { 
            service.storePayment(dto); //request from a client
        }
    
        public PaymentDTO getPayment(int paymentId) { 
            return service.getPayment(paymentId); //response to a client
        }
    }
    
          

  • the service layer (also called the business layer responsible for business logic - knows what to do with incoming messages, but doesn't know where they came from).

    public class TestServiceImpl {
        @Autowired
        private TestDao dao;
    
        @Transactional(propagation=Propagation.REQUIRED) //force transaction
        public void storePayment(PaymentDTO paymentDto) {
            // transform dto -> entity
            dao.storePayment(paymentEntity); //read-write hence transaction is on
        }
    
        @Transactional(propagation=Propagation.NOT_SUPPORTED) //avoid transaction
        public Payment getPayment(int paymentId) {
            return dao.findPayment(paymentId); //read-only hence no transaction
        }
    }
    
          

  • Data access layer (also called persistence layer, responsible for database access - knows how to use the entity model / ORM, knows nothing about the top layer of the service)

    public class TestDAOImpl {
        @PersistenceContext
        private EntityManager em;
    
        public void storePayment(PaymentEntity paymentEntity) {
            em.persist(paymentEntity);
        }
    
        public PaymentEntity getPayment(int paymentId) {
            return em.find(PaymentEntity.class, paymentId);
        }
    }
    
          



With this approach, you get a separation of the issues mentioned in the post. On the other hand, this approach (business layer and data access layer) received a small dose of criticism from Adam Bien's blog ("JPA / EJB3 killed the DAO"). As you can see, there is no single solution to the problem, but I recommend reading some of the other opinions and applying the solution that you find most suitable for your needs.

+5


source


When you call the two Tao methods first and second from the controller, two transactions will be executed, one of which starts before the first method and ends after it is executed, and the second starts before the second method starts and finishes after it is executed. While you create an additional class between the controller and the dao (usually called the service level) and annotate it with @Transactional and call several Dao methods in it, the transaction starts at the beginning of the service method and all dao calls will be and the transaction will be closed what you need. And enter Service into Controller.

Controller -> Service -> Tao



@Controller
@RequestMapping("/data")
public class PaymentTransaction {

    @Autowired
    private TestService service;

    @RequestMapping(value = "/test", method = RequestMethod.POST)
    @ResponseBody()
    public String test(HttpServletRequest request) {

      ...

    }
}

@Service
@Transactional
public class TestService {

    @Autowired
    private TestDao dao;

    @Transactional
    public void serviceCall(){
         dao.first();
         dao.second();
    }

}

      

+1


source







All Articles