Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA:使用服务和多个存储库的正确方法_Java_Spring_Jpa_Spring Data Jpa - Fatal编程技术网

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

Java JPA:使用服务和多个存储库的正确方法,java,spring,jpa,spring-data-jpa,Java,Spring,Jpa,Spring Data Jpa,我制作了一个使用JPA和Spring的系统。例如,如果我需要处理帐户,我会使用存储库: @Repository public interface AccountRepository extends JpaRepository<Account, Long> class AccountServiceImpl implements AccountService { @Autowired private AccountRepository repository; @Tran

我制作了一个使用JPA和Spring的系统。例如,如果我需要处理帐户,我会使用存储库:

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

...
现在,我创建了一个控制器,用于处理帐户的POST方法:

@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) {
现在我的问题是:为每个存储库调用save方法的正确方法是什么

1) 我是否应该在控制器中创建类,然后为创建的每个类调用save方法:

@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) 在RegistrationService中调用每个服务的保存:

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) 在RegistrationService中调用每个存储库的保存:

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)感到困惑

问题又来了:

我是否应该/可以在服务中使用其他服务?或者我必须在服务中只使用存储库


用谷歌搜索这一解释的正确方法是什么?对不起,英语不是我的母语,我找不到正确的方式询问这种设计。

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

服务

服务层是您将数据传输对象转换为实体的地方,反之亦然。控制器接收可能/可能不直接映射到数据库实体的数据对象。此转换由服务层完成。 在您的情况下,控制器会收到
注册

因此,最好的方法是让您的控制器调用注册服务,并将接收到的数据对象传递给它进行处理

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


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

我更喜欢把这些顾虑分开

e、 g只有AccountsService应该知道帐户存储库的进出。账户服务应该像处理账户的中间人一样。你想保存它吗?把它给我。你想找到它吗?我会帮你找的


简而言之,我更喜欢RegistrationService调用其他服务,而不是直接调用存储库

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

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

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

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

使用特定于实体的服务时存在一个问题:在控制器中逐个调用它们意味着每个服务都使用自己的事务。创建事务的速度很慢,并且使用单独的事务可能会导致数据不一致。将您的业务逻辑放在一个事务中会限制您对一致性问题的暴露,仅限于与事务隔离级别相关的问题

我也不同意服务应该在DTO和实体之间转换的观点。偶尔您可能会发现需要dto,但这不应该是例行公事。对于使用JSP或thymeleaf的web应用程序,您可以愉快地添加实体作为请求属性,并让模板直接使用它们。如果您的控制器需要返回JSON,您可以连接messageconverter直接从实体生成JSON,或者最好使用dto。尽量将重点放在实现业务功能上,避免将数据从一种持有者移动到另一种持有者,因为这种代码脆弱且容易出错


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

可以将事务划分作为一个起点。服务为存储库处理事务。谷歌建议:spring采用域驱动设计的术语,你可以在谷歌上搜索域驱动设计或DDD以及服务或存储库等术语,以获得更多的概念性解释。我同意你的观点,即使用聚合服务包含其他服务来完成复杂的逻辑。但是要确保服务之间的依赖关系。如果你这样做,你将需要在域服务中重复存储库的功能。我不确定这种方法,因为