spring-mvc - Spring Data JPA - Java 8 流支持和事务最佳实践

标签 spring-mvc java-8 spring-data spring-data-jpa java-stream

我有一个非常标准的 MVC 设置,其中包含用于我的 DAO 层的 Spring Data JPA 存储库、一个处理事务问题和实现业务逻辑的服务层,以及一个具有一些可爱的基于 REST 的 JSON 端点的 View 层。

我的问题是关于 Java 8 的大规模采用 Stream进入这个可爱的架构:如果我所有的 DAO 都返回 Stream s,我的服务返回相同的 Stream s(但做事务性工作),而我的观点则作用于并处理这些 Stream s,然后当我的 View 开始处理我的 Stream 中的模型对象时s,Service层创建的事务将被关闭。如果底层数据存储还没有实现我所有的模型对象(毕竟它是一个 Stream,尽可能懒惰),那么我的 View 将在尝试访问事务之外的新结果时出错。以前这不是问题,因为我会将结果完全具体化到列表中 - 但现在我们进入了 Stream 的美丽新世界。 s。

那么,处理这种情况的最佳方法是什么?将Service层内部的结果完全物化为List并交还? View 层是否将完成块交给服务层,以便可以在事务内部完成进一步处理?

谢谢您的帮助!

最佳答案

考虑到这一点,我决定尝试我在问题中提到的完成块解决方案。我所有的服务方法现在都有一个结果转换器作为它们的最终参数,它接受模型对象的流并将其转换为 View 层需要/请求的任何结果类型。我很高兴地报告它就像一种魅力,并且有一些很好的副作用。

这是我的服务基类:

public class ReadOnlyServiceImpl<MODEL extends AbstractSyncableEntity, DAO extends AbstractSyncableDAO<MODEL>> implements ReadOnlyService<MODEL> {

    @Autowired
    protected DAO entityDAO;

    protected <S> S resultsTransformer(Supplier<Stream<MODEL>> resultsSupplier, Function<Stream<MODEL>, S> resultsTransform) {
        try (Stream<MODEL> results = resultsSupplier.get()) {
            return resultsTransform.apply(results);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public <S> S getAll(Function<Stream<MODEL>, S> resultsTransform) {
        return resultsTransformer(entityDAO::findAll, resultsTransform);
    }

}
resultsTransformer这里的方法温和地提醒子类不要忘记 try-with-resources 模式。

这是调用服务基类的示例 Controller :
public abstract class AbstractReadOnlyController<MODEL extends AbstractSyncableEntity, 
                                                 DTO extends AbstractSyncableDTOV2, 
                                                 SERVICE extends ReadOnlyService<MODEL>> 
{

    @Autowired
    protected SERVICE entityService;

    protected Function<MODEL, DTO> modelToDTO;

    protected AbstractReadOnlyController(Function<MODEL, DTO> modelToDTO) {
        this.modelToDTO = modelToDTO;
    }

    protected List<DTO> modelStreamToDTOList(Stream<MODEL> s) {
        return s.map(modelToDTO).collect(Collectors.toList());
    }

    // Read All
    protected List<DTO> getAll(Optional<String> lastUpdate) 
    {
        if (!lastUpdate.isPresent()) {
            return entityService.getAll(this::modelStreamToDTOList);
        } else {
            Date since = new TimeUtility(lastUpdate.get()).getTime();
            return entityService.getAllUpdatedSince(since, this::modelStreamToDTOList);
        }
    }
}

我认为让 Controller 通过 Java 8 lambda 来决定服务的返回类型是对泛型的一种非常巧妙的使用。虽然我看到 Controller 直接返回 Service 调用的结果很奇怪,但我很欣赏这段代码的紧凑性和表现力。

我想说这是尝试大规模切换到 Java 8 Streams 的积极因素。希望这可以帮助有类似问题的人。

关于spring-mvc - Spring Data JPA - Java 8 流支持和事务最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36734581/

相关文章:

java - 使用 StreamSupport 库时 Dex 失败

cassandra - Spring Data Cassandra 插入创建单元墓碑

elasticsearch - ElasticSearchRepository deleteBy在单元测试中不起作用

java - Spring 自定义基于条件的验证

java - 在几秒钟内从 Spring MVC 中的表中获取 400K 数据

java - 如何调试 Spring MVC tomcat 应用程序?

spring-mvc - Spring-boot 从 Controller 返回 json 和 xml

java - 如何正确地将流减少到另一个流

java - 如何在 Java-8 中显示普通纪元 ("CE")?

java - Spring JPA审计空createdBy