我们应该在哪里使用@Transactional以及Service层在哪里?

gre*_*rep 3 spring jpa spring-mvc

我在Spring有休息风格控制器.在控制器中我注入了dao接口.从控制器我坚持数据.换句话说,我喜欢REST Web服务.人们发给我数据,我坚持下去.

/**
 * 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) {

    ...

    }
Run Code Online (Sandbox Code Playgroud)

目前我在Dao类中有@transaction注释.例如:

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

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

    }
Run Code Online (Sandbox Code Playgroud)

我读过这是非常糟糕的风格.在stackoverflow上使用这个答案,这里有解释和示例为什么这很糟糕 - 我们不能在DAO和控制器中添加这个注释.我们必须在服务层添加它.

但我不明白什么是服务层?或者在哪里?我没有这样的东西.我应该在哪里写@Transactional注释?

最好的祝福,

wyp*_*prz 5

根据引用的帖子,你应该像这样设计你的类(而不是伪代码):

  • 控制器(负责处理客户的请求/响应)

    @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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 服务层(也称为业务层,负责业务逻辑 - 知道如何处理传入的消息,但不知道它们来自何处).

    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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 数据访问层(也称为持久层,负责访问数据库 - 知道如何使用实体模型/ ORM,对上层服务层一无所知)

    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);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

通过这种方法,您可以分离帖子中提到的问题.另一方面,这种方法(业务层与数据访问层)得到了Adam Bien在其博客上的批评(" JPA/EJB3杀死了DA O").正如您所看到的,该问题没有一个解决方案,但我鼓励您阅读其他一些意见并应用您认为最适合您需求的解决方案.