در حال حاضر Spring Data از ویژگی های جدید جاوا 8 مانند Stream API , Optional , CompletableFuture حمایت میکند و در این بخش خواهیم دید که چگونه میتوان از آنها در Spring Data استفاده کنیم
public interface CrudRepository<T, ID> extends Repository<T, ID> { Optional<T> findById(ID id); }
public interface UserRepository extends JpaRepository<User, Integer> { Optional<User> findOneByName(String name); }
Stream API :
در قبل اگر نتیجه کوئری که برگشت داده میشد بیش از یکی بود آنرا در یک Collection مانند List دریافت میکردیم :
public interface UserRepository extends JpaRepository<User, Integer> { // ... List<User> findAll(); // ... }
که یکی از مشکلات آن مصرف بیش از حد حافظه است. کلیه Result ها یکباره دریافت و در حافظه نگهداری میشود
و میتوان List را با Page جایگزین کنیم :
public interface UserRepository extends JpaRepository<User, Integer> { // ... Page<User> findAll(Pageable pageable); // ... }
در اغلب سناریوها Page جوابگو هست و استفاده از آن مشکل مشهودی ایجاد نمیکند ولی در مواردی مانند Pagination که درخواست های زیاد و Result ها هم زیاد است جوابگو نیست
ولی با استفاده از Stream میتوانیم جریانی از داده را فراهم کنیم :
public interface UserRepository extends JpaRepository<User, Integer> { // ... Stream<User> findAllByName(String name); // ... }
Spring Data موقعی که از Stream استفاده میکند نوع خاصی از آن را بکار میگیرد در Hibernate از ScrollableResultSet و در EclipseLink از ScrollableCursor استفاده میکند که نوع خاصی از پیاده سازی Stream هستند و حافظه کمتر و تعداد کوئری کمتری را شامل میشود برای همین از List و Page بهینه تر و سریعتر هست
موقع استفاده از Stream در آخر نیاز است که close شود که بوسیله متد ()close انجام میشود
همچنین متد های Repository را باید همراه با Transaction اجرا کنیم وگرنه خطایی مشابه زیر رخ خواهد داد :
org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.
@Async CompletableFuture<User> findOneByStatus(Integer status);