代码之家  ›  专栏  ›  技术社区  ›  Mariano L

JPA:正确使用服务和多个存储库的方法

  •  2
  • Mariano L  · 技术社区  · 6 年前

    @Repository
    public interface AccountRepository extends JpaRepository<Account, Long>
    

    然后创建一个使用存储库的服务:

    class AccountServiceImpl implements AccountService {
    
      @Autowired
      private AccountRepository repository;
    
      @Transactional
      public Account save(Account account){
        return repository.save(account);
      }
    
    ...
    

    @Controller
    public class AccountController {
    
    @Autowired    
    private final accountService service;
    
    @RequestMapping(value = "/account", method = RequestMethod.POST)
            public ModelAndView account(@Valid Account account, BindingResult bindingResult) {
        ...
    service.save(account);
    

    对客户、产品、联系人等也一样。

    现在,假设我还有一个名为“registration”的类,它包含足够的数据来创建一个客户,包括他的帐户、联系人数据和产品(大量数据)。注册的“确认”操作是专门用于执行以下操作的操作:

    @RequestMapping(value = "/confirm", method = RequestMethod.POST)
        public ModelAndView confirmRegistration(@Valid Registration registration, BindingResult bindingResult) {
    

    现在我的问题是: 正确的方法是什么 节约 每个存储库的方法?

    控制器

    @RequestMapping(value = "/confirm", method = RequestMethod.POST)
            public ModelAndView confirmRegistration(@Valid Registration registration, BindingResult bindingResult) {
    ...
    customerService.save(customer);
    accountService.save(account);
    contactDataService.save(contactData);
    productService.save(contactData);
    ...
    

    2) 调用每个服务的保存 :

    class RegistrationServiceImpl implements RegistrationService {
    
      @Autowired
      private AccountService accountService;
      @Autowired
      private CustomerService customerService;
      ....
    
      @Transactional
      public void confirm(Registration registration){
      ... here I create the object
      customerService.save(customer);
      accountService.save(account);
      }
    

    3) 为每一个 在注册服务中:

    class RegistrationServiceImpl implements RegistrationService {
    
      @Autowired
      private AccountRepository accountRepository;
      @Autowired
      private CustomerRepository customerRepository;
      ....
    
      @Transactional
      public void confirm(Registration registration){
      ... here I create the object
      customerRepository.save(customer);
      accountRepository.save(account);
      }
    

    如果我必须使用(1),我会理解。但对选项(2)和(3)感到困惑。

    问题又来了:

    我应该/可以在服务中使用其他服务吗?或者我只能在服务中使用存储库?

    谷歌的正确解释是什么?抱歉,英语不是我的母语,我找不到正确的方式来询问这种设计。

    2 回复  |  直到 6 年前
        1
  •  5
  •   Nathan Hughes    6 年前

    服务并不总是必须是事务性的,但是当您使用JPA进行数据库工作时,事务是非常重要的,因为事务确保您的更改可以预测地提交,而不会受到其他并发工作的干扰。Spring使您的服务易于事务化,确保您理解事务,以便您可以充分利用它们。

    在服务中使用服务,您可以设置事务传播,以便它们都使用同一事务,也可以使用单独的事务,这两种情况都有有效的情况。但我建议你不要做你在这里做的事。

    服务是放置业务逻辑的地方,特别是需要事务性(全部或无事务性)的业务逻辑。根据功能将逻辑组织到服务中是有意义的,这样服务方法就是用户在某些特定部分所采取的操作。

    但是为每种类型的实体提供服务并不是很有用,我建议不要这样做。一个服务可以有任意数量的存储库,您不必将每个存储库包装在自己的服务中。(教程显示特定于实体的服务,或者它们可能完全跳过服务层,这是因为它们希望向您展示框架功能,并最小化业务逻辑。但真正的应用程序往往有很多业务逻辑。)

    使用实体特定服务的一个问题是:一个接一个地在控制器中调用它们意味着每个服务都使用自己的事务。创建事务的速度很慢,如果有单独的事务,可能会导致数据不一致。将业务逻辑放在一个事务中会将一致性问题的风险限制为与事务隔离级别相关的问题。

    对于控制器和服务之间的差异,我有答案 here here .

        2
  •  5
  •   Amit Phaltankar    6 年前

    控制器 理想情况下,控制器只能接受HTTP请求并提供响应。如果数据保存在数据库或文件中,或者通过另一个HTTP调用发送到另一个服务,那么控制器就不必费心。 始终让控制器远离任何业务。

    服务

    在您的情况下,您的控制器接收 Registration

    所以最好的方法是让你的控制器直接调用 RegistrationService 并将接收到的数据对象传递给它进行处理。

    现在注册服务的工作是将数据对象转换为数据库实体并将它们保存在事务中。


    服务中的存储库?

    我更喜欢把问题分开。

    e、 g只有AccountsService才应该知道Accounts存储库的输入和输出。帐户服务应该充当处理帐户的中间人。你想保存它吗?把它给我。你想找到它吗?我会帮你找到的。