Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should we use @Transactional and where is Service layer?

I have rest style controller in Spring. In controller I have injected dao interfaces. From controller I persist data. In the other words, I have like REST web service. people sends me data, and I persits 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 instance:

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

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

    }

I have read that this is very bad style. Using this answer at stackoverflow , here is explain and examples why is this bad - we must not add this annotation in DAO and in controller too. We must add it in service layer.

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

Best regards,

like image 456
grep Avatar asked Mar 19 '23 03:03

grep


1 Answers

According to the cited post, you should design your classes somehow like this (rather pseudocode):

  • controller (responsible for handling clients' requests/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
        }
    }
    
  • service layer (also called business layer, responsible for business logic - knows what to do with incoming messages, but does not know where they come 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 accessing database - knows how to use entity model / ORM, does not know anything about the upper service layer)

    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);
        }
    }
    

By this approach you get separation of concerns mentioned in the post. From the other hand such an approach (business layer vs data access layer) got a little dose of criticism from Adam Bien's on his blog ("JPA/EJB3 killed the DAO"). As you can see there is no a single solution for the problem, but I encourage to read some other opinions and apply the solution you find the most suitable for your needs.

like image 72
wypieprz Avatar answered Apr 05 '23 20:04

wypieprz