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

时间:2014-10-21 16:31:17

标签: spring spring-mvc jpa

我在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) {

    ...

    }

目前我在Dao课程中有@transaction注释。例如:

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

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

    }
stackoverflow上的

I have read that this is very bad style. Using this answer,这里有解释和示例为什么这很糟糕 - 我们不能在DAO和控制器中添加这个注释。我们必须在服务层添加它。

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

致以最诚挚的问候,

2 个答案:

答案 0 :(得分:5)

根据cited帖子,您应该以某种方式设计您的类(相当于伪代码):

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

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

    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
        }
    }
    
  • 数据访问层(也称为持久层,负责访问数据库 - 知道如何使用实体模型/ 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);
        }
    }
    

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

答案 1 :(得分:2)

当你先打电话给两个Dao方法时第二个来自控制器,将完成2个事务,一个在第一个方法之前开始并在它执行之后结束,第二个在第二个方法开始之前开始并在它执行之后结束。您在控制器和dao之间创建了一个额外的类(通常称为服务层),并使用@Transactional对其进行注释并在其中调用多个Dao方法,然后在服务方法开始时启动事务,所有dao调用将是执行和交易将被关闭,这是您所需要的。并将服务注入Controller。

控制器 - &gt;服务 - &gt;道

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

}