Share
Embed
Java Data Access Performance in Combination with Vaadin and REST API
Simon Martinelli PRO
January 09, 2022
Transcript
26 slides
-
Java Data Access Performance in Combination with Vaadin and REST
API Simon Martinelli, 72 Services LLC -
8 In-Memory vs Lazy Callbacks • In-Memory • Easy to
use if you only have a handful of items • Lazy callbacks • For larger amount of data List<Customer> customers = customerRepository.findAll(); grid.setItems(customers); grid.setItems(query -> customerRepository.findAll( PageRequest.of(query.getPage(), query.getPageSize()) ).stream() ); -
9 The Query Object int getOffset(); int getLimit(); int getPage();
int getPageSize(); List<QuerySortOrder> getSortOrders(); Optional<F> getFilter(); -
10 Paging and Sorting • List<QuerySortOrder> getSortOrders() provides the sorted
columns with sort direction (ascending or descending) • VaadinSpringDataHelpers.toSpringDataSort() converts the Query to a Spring Data Sort object grid.setItems(query -> customerRepository.findAll(PageRequest.of(query.getPage(), query.getPageSize(), toSpringDataSort(query)) ).stream() ); -
11 Lazy Data View • Provide an optional CountCallback to
improve scrollbar behavior • Take care of performance because of the additional count query! grid.setItems( query -> customerRepository.findAll( PageRequest.of(query.getPage(), query.getPageSize(), toSpringDataSort(query))).stream(), query -> (int) customerRepository.count() ); -
12 Item Count Estimate • If you can’t implement a
CountCallback you can set estimates: GridLazyDataView<Employee> dataView = grid.setItems( query -> employeeRepository .findAll(PageRequest.of(query.getOffset(),query.getLimit())) .stream()); dataView.setItemCountEstimate(1000); dataView.setItemCountEstimateIncrease(500); -
13 Filtering • ComboBox is filterable out of the box
• In Grids with lazy fetching we can use the filter in the FetchCallback filter = new TextField(); filter.setValueChangeMode(ValueChangeMode.LAZY); filter.addValueChangeListener(event -> loadData(event.getValue())); private void loadData(String name) { grid.setItems( query -> customerRepository.findAllCustomersWithRevenue( PageRequest.of(query.getPage(), query.getPageSize(), toSpringDataSort(query)), name).stream() ); } -
14 ConfigurableFilterDataProvider • With ConfigurableFilterDataProvider you can pass a filter
CallbackDataProvider<CustomerInfo, String> callbackDataProvider = DataProvider.fromFilteringCallbacks( // FetchCallback query -> customerRepository.findAllCustomersWithRevenue( PageRequest.of(query.getPage(), query.getPageSize(), toSpringDataSort(query)), query.getFilter().orElse("")).stream(), // CountCallback query -> customerRepository.countAllByLastnameLikeOrFirstnameLike(query.getFilter().orElse("")) ); // Set the DataProvider ConfigurableFilterDataProvider<CustomerInfo, Void, String> dataProvider = callbackDataProvider.withConfigurableFilter(); grid.setDataProvider(dataProvider); // Use the filter filter.addValueChangeListener(event -> { dataProvider.setFilter(event.getValue()); }); -
15 Identity Provider • Vaadin uses equals() to identify an
object • What if the object doesn't implement equals()? • Define an identifierGetter new CallbackDataProvider<>( query -> employeeRepository.findAll( PageRequest.of(query.getOffset(), query.getLimit())) .stream(), query -> employeeRepository.count(), Employee::getId // Identifier! ); -
16 Refreshing • You can refresh all or just one
element grid.getLazyDataView().refreshAll(); grid.getLazyDataView().refreshItem(employee); -
17 Hierarchical Data Provider new AbstractBackEndHierarchicalDataProvider<>() { @Override public int
getChildCount(HierarchicalQuery<Employee, Void> query) { if (query.getParent() == null) { return employeeRepository.countBySupervisorIsNull(); } else { return employeeRepository.countBySupervisor(query.getParent()); } } @Override public boolean hasChildren(Employee employee) { return employeeRepository.countBySupervisor(employee) > 0; } @Override protected Stream<Employee> fetchChildrenFromBackEnd(HierarchicalQuery<Employee, Void> query) { if (query.getParent() == null) { return employeeRepository.findAllBySupervisorIsNull().stream(); } else { return employeeRepository.findAllBySupervisor(query.getParent()).stream(); } } }; -
18 Data Provider and JPA/Hibernate • JPA Entities can be
used • BUT be aware of lazy loading and the n+1 select problem! • Consider using projection with DTOs • Java 16 Records are a great fit public record CustomerInfo(Long id, String lastname, String firstname, double revenue) { } -
20 Stop Mapping Stuff in Your Middleware • Modern databases
provide functions to return XML or JSON data • Often it’s not necessary to make a detour using objects • https://blog.jooq.org/2019/11/13/stop-mapping-stuff-in-your-middleware-use-sqls- xml-or-json-operators-instead/ • https://www.youtube.com/watch?time_continue=973&v=wTPGW1PNy_Y -
21 JSON Query select json_agg(po) as orders from (select p.id,
p.order_date, (select json_agg(oi) from (select i.id, i.quantity, pr.name as product from order_item as i join product pr on pr.id = i.product_id where i.order_id = p.id ) oi ) as items from purchase_order as p where p.customer_id = ?) po -
22 JSON Result [ { "id": 6232, "order_date": "2021-05-07", "items":
[ { "id": 32446, "quantity": 7, "product": "Pencil" }, { "id": 32447, "quantity": 7, "product": "Pencil" } } ] -
23 XML Query select xmlelement( name "orders", xmlagg(xmlelement(name "order", xmlattributes(p.id,
p.order_date), xmlelement(name "items", (select xmlagg(xmlelement(name "item", xmlattributes(i.id, i.quantity, pr.name))) from order_item i join product pr on i.product_id = pr.id where i.order_id = p.id))) ) ) from purchase_order p where p.customer_id = ? -
24 XML Result <orders> <order id="6232" order_date="2021-05-07"> <items> <item id="32446"
quantity="7" name="Pencil"/> </items> </order> </orders> -
25 Conclusion • Displaying data with Vaadin is very easy
but use lazy data providers to reduce memory size and enhance performance • Use projection with DTOs or Records instead of JPA Entities • Consider using SQL -
26 72 Services GmbH Tulpenweg 1 2575 Täuffelen, Switzerland +41
32 544 88 88 [email protected] https://72.services