简体   繁体   中英

Spring Data JPA - return Future

I tried to save my entity asynchronous and return future of the result, but I had following problems:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.Repository;
import org.springframework.scheduling.annotation.Async;
//import org.springframework.stereotype.Repository;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

// I must extend Repository because when I extended JpaRepository an argument 
// of save is ambigous when I try save(countryEntity) - compiler shows me 
// save (CountryEntity) in AsyncCountryRepository and save (S) in CrudRepository
public interface AsyncCountryRepository extends Repository<CountryEntity, Long> {

    // I don't know why I cannot return Future<CountryEntity>
    @Async
    <S extends CountryEntity> Future<S> save(CountryEntity countryEntity);

    // I cannot test it - test is below
    @Async
    CompletableFuture<CountryEntity> findByCode(String code);

}


@RunWith(SpringRunner.class)
@DataJpaTest
public class CountryRepositoryTest {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private AsyncCountryRepository countryRepository;

    @Test
    public void findByCodeTest() throws Exception {
        // given
        final CountryEntity countryEntity = new CountryEntity("EN");

        final CountryEntity persisted = entityManager.persist(countryEntity);
        entityManager.flush();

        // when
        final Future<CountryEntity> byCode = countryRepository.findByCode(persisted.getCode());

        // then
        assertThat(byCode.get())
                .isEqualTo(persisted);
    }

Test returns Failed and I get expected:<CountryEntity(id=1, code=EN)> but was:<null>

How can I implement my repository as asynchronous repository and how to test it?

Which approach has better performance: 1. return Futures from repository 2. run repository methods as Callable in ExecutorService ?

If you use @Async the repository code runs in a separate thread within it's own transaction. Since your original transaction isn't committed, it won't see the changes (ie the inserted entity) hence the null result.

So in order to make it work, you need to commit the first transaction.

Regarding the second question about the performance (Please make separate questions next time): Performance of multithreaded code depends on so many things that really the only useful way to answer it: try it. But I would be surprised if the way how you schedule the execution has more effect on the performance than things like thread pool and connection pool size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM