在事务外访问数据的模式

时间:2018-06-26 05:08:37

标签: spring hibernate spring-data-jpa spring-transactions

我有一个带有Spring Data JPA的Spring Boot应用,该应用具有hibernate和MySQL作为数据存储。

我的应用程序具有3层:

  1. API服务
  2. 应用服务
  3. 域服务(带有存储库)

应用服务的作用是在给定一些业务逻辑的情况下将支持休眠的POJO转换为DTO。

POJO

SchoolClass.java

@Column
Long id;

@Column
String name;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Book> books;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Student> students;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Schedule> schedules;

域服务-我的交易边界在域服务层。

SchoolClassService.java

@Autowired
private SchoolClassRepository repository;

@Transactional(readOnly = true)
public SchoolClass getClassById(Long id) {
  return repository.findById(id);
}

应用服务

SchoolClassAppService.java

@Autowired
private SchoolClassService domainService;

public SchoolClassDto getClassById(Long id) {
  SchoolClass schoolClass = domainService.getClassById(id);
  // convert POJO to DTO;
  return SchoolClassDto;
}

我的问题是,当我尝试在SchoolClassAppService中访问它们时,SchoolClass上的子实体有时为空。不是全部,但是在这三个中,两个可以正常工作,但是第三个是空的。我试图标记要急切获取的子级列表,但是显然,在Hibernate开始引发异常之前,只能急切地获取两个集合,而且始终加载所有对象听起来也不是一种好习惯。我没有得到LazyInitializationException,只是列表为空。

我试图只在域服务方法中的所有列表上调用getter,然后再返回它以仅加载POJO的所有数据,但这似乎不是一种干净的做法。

是否有任何可用的模式可以使事务边界尽可能靠近持久层,同时即使在事务关闭后仍然可以处理数据?

1 个答案:

答案 0 :(得分:1)

不知道为什么有时您的收藏集为空,但也许只是数据如何?

我正是为此用例创建了Blaze-Persistence Entity Views。您实际上将JPA实体的DTO定义为接口,并将其应用于查询。它支持映射嵌套的DTO,集合等,本质上是您期望的所有内容,此外,它还将提高查询性能,因为它将生成查询,仅提取您实际为DTO所需的数据。

您的示例的实体视图如下

@EntityView(SchoolClass.class)
interface SchoolClassDto {
  String getName();
  List<BookDto> getBooks();
}
@EntityView(Book.class)
interface BookDto {
  // Whatever data you need from Book
}

查询看起来像这样

List<SchoolClassDto> dtos = entityViewManager.applySetting(
  EntityViewSetting.create(SchoolClassDto.class),
  criteriaBuilderFactory.create(em, SchoolClass.class)
).getResultList();

请记住,DTO不仅应复制您的实体,还应设计为适合您的特定用例。