- Java EE 8 High Performance
- Romain Manni Bucau
- 409字
- 2021-06-30 19:14:24
The service layer
The goal of the book being to discuss the performance and not how to write a Java EE application, we will not detail the whole service layer here. However, to ensure a common knowledge of what we are dealing with, we will illustrate the code with one service.
We are using JTA 1.2 with JPA 2.2 to establish a link between our database and the Java model. The QuoteService bean, responsible for managing the Quote persistence, can therefore look like the following:
@Transactional
@ApplicationScoped
public class QuoteService {
@PersistenceContext
private EntityManager entityManager;
public Optional<Quote> findByName(final String name) {
return entityManager.createQuery("select q from Quote q where
q.name = :name", Quote.class)
.setParameter("name", name)
.getResultStream()
.findFirst();
}
public Optional<Quote> findById(final long id) {
return Optional.ofNullable(entityManager.find(Quote.class, id));
}
public long countAll() {
return entityManager.createQuery("select count(q) from Quote
q", Number.class)
.getSingleResult()
.longValue();
}
public Quote create(final Quote newQuote) {
entityManager.persist(newQuote);
entityManager.flush();
return newQuote;
}
// ... other methods based on the same model
}
JPA may or may not be used in a transactional context, depending on the kind of operation you do. When you read data, you can often do it without any transaction until you need some lazy loading. However, when you write data (insert/update/delete entities), JPA requires a running transaction to be able to execute the action. This is to ensure consistency of data but also has some implications on the code. To respect that requirement, and have an active transaction, we use @Transactional on methods instead of relying on Enterprise Java Bean 3.2 (EJB 3.2), so we can reuse the power of CDI (@ApplicationScoped, for instance, which will avoid creating a new instance per injection).
Our finders are very simple and directly use the EntityManager API. The only new thing Java 8 brings us in this code is the ability to wrap the result with Optional which offers a programmatic way to deal with the presence or absense of the entity instead of relying on a null check. Concretely, the caller can use our finder this way:
final int quoteCount = getCustomer().getCountFor("myquote");
final double quotesPrice = quoteService.findByName("myquote")
.map(quote -> quote.getValue() * quoteCount)
.orElse(0);
This kind of code hides the conditional branches behind a fluent API, which makes it more expressive and readable, while the lambdas stay small enough.
Finally, we used inline queries in this code, not static ones like in the @NamedQuery API.