播放2.6-Java-交易管理

时间:2018-08-09 18:21:29

标签: playframework-2.6

我尝试在Play2(目前为2.6.15版)中迁移Play1应用程序。

使用Play1,在请求到达时自动管理交易。因此,我不必担心数据库更新的一致性。数据库更新已在整个服务层完成。

我必须将这种逻辑保留在Play2中,但我不确定该怎么做。我看到了Scala的一些线索,但答案无济于事。所以我会抓住机会的:)

要了解它是如何工作的,我编写了一个包含两个二进制模型的代码段:人员和地址。我想保存一个人及其地址列表和回滚,以防其中一个请求发生错误。

开始迁移时,我受到play-java-jpa-example的启发:我创建了一些存储库,其中包含基于JPAApi并在DatabaseExecutionContext上执行的对数据库的所有访问权限

public class PersonRepository implements IPersonRepository {

    private final JPAApi jpaApi;
    private final DatabaseExecutionContext executionContext;

    @Inject
    public PersonRepository(JPAApi jpaApi, DatabaseExecutionContext executionContext) {
        this.jpaApi = jpaApi;
        this.executionContext = executionContext;
    }
    ...
    @Override
    public CompletionStage<Person> add(Person person) {
        return supplyAsync(() -> jpaApi.withTransaction(em -> {
            em.persist(person);
            return person;
        }), executionContext);
    }
}

public class AddressRepository implements IAddressRepository {
    ...
    @Override
    public CompletionStage<Address> add(Address address) {
        return supplyAsync(() -> jpaApi.withTransaction(em -> {
            em.persist(address);
            return address;
        }), executionContext);
    }
}

我有一项保存地址的服务

public class AddressService implements IAddressService {
    ....
    @Override
    public CompletionStage<Address> add(Address address) {
        //do some stuff here
        return addressRepository.add(address);
    }
}

以及用于保存人的服务,

public class PersonService implements IPersonService {
    ...
    @Override
    public CompletionStage<Person> add(Person person, List<Address> address) {
        return add(person).thenApplyAsync(p -> {
            for (Address a : address) {
                a.person=p;
                addressServiceAsync.add(a);
            }
            return p;
        }, ec.current());
    }
}

使用add(Person person,List address)的这种实现,如果保存第二个地址失败,则该人和第一个地址将被保存在数据库中,这对我来说不够好。

我试图删除存储库中的事务管理并将其放在我的PersonService.add函数中。通过将实体管理器传递给我的服务和存储库的功能,它可以工作(我仅使用同步调用进行了测试)。像这样的东西:

 public class PersonService implements IPersonService {
    @Override
    public CompletionStage<Person> add(Person person, List<Address> address) {
        return supplyAsync(() -> jpaApi.withTransaction(em -> {
            Person person1 = personRepository.insert(em, person);
            for (Address a : address) {
                a.person = person1;
                addressService.add(em, a);
            }
            return person1;
        })).exceptionally(throwable -> {
            Logger.error("pan", throwable);
            return null;
        });
    }
}

我不喜欢这种方法(将所有功能都赋予它们)并且想知道异步调用。

在Play中计划如何处理JPAApi和DatabaseExecutionContext这种回滚问题?

我没有看到任何明确的线索引起这一点,也许我错过了一些东西。解决此问题的最佳实践是什么?

感谢您的帮助。

0 个答案:

没有答案