Twitter

duminică, 31 iulie 2016

PrimeNG DataTable Lazy pagination (and sorting) and Spring Data Rest (HATEOAS) via Hibernate JPA

We suppose that we have a simple table that contains the products from figure below:


Further, we expose the data from this table via Spring Data REST. So, a request of type: http://localhost:8080/SHPaginating/items/?size=5 will produce a JSON response as below:


Now, we want to use PrimeNG DataTable Lazy to display data using pagination and sorted by item name as below:


And some HATEOAS information that you can use for further implementations:


The complete example is available here. First, you need to run npm install in \SHPaginating\src\main\webapp.  The app is a WAR that can be tested under e.g. Payara.

joi, 28 iulie 2016

HHH-5855 was fixed starting Hibernate 5.0.8

Conclusions at the beginning:

1. Update your Hibernate version to the final release.
2. Read A beginner’s guide to Hibernate Set and List behavior by Vlad Mihalcea (especially if update is not an option for you)

Why?

The Hibernate HHH-5855 causes an output like below:

BEFORE Hibernate 5.0.8:

Fire inserts:


Fire updates:


A complete example to play with is available here.

AFTER Hibernate 5.0.8:

Fire inserts:


Fire updates:


A complete example to play with is available here.

What's the difference between non-identifying and identifying relationship

Knowing the difference between non-identifying and identifying relationship is useful when we need to decide which one we need. So, in a very simple explanation, is like this:

Non-identifying  relationship:
A person may own a house (or multiple houses). But, after a while, the person may sell the house to another person (owner). So, the house may exist without a owner or can change multiple owners in time. This is a non-identifying  relationship.

Identifying  relationship:
The sure thing is that a house must be built by a constructor (of course, the constructor has probably built multiple houses) and without that constructor the house would not have existed. This is the identifying  relationship.

miercuri, 27 iulie 2016

Hibernate session-level batching via Spring MVC example

Thanks to Hibernate team (especially to Vlad Mihalcea) starting with version 5.2 we have support for session-level batching. Basically, this is possible via Session#setJdbcBatchSize() and Session#getJdbcBatchSize(). In order to build an example via Spring MVC, you will need Hibernate 5.2 and Spring 4.3.1. The relevant part of the code is:

productDAO.persistWithBatching(n, 10);
...

And ...

@Override
public void persistWithBatching(int n, int batchsize) {

 Session session = getEntityManager().unwrap(Session.class);
 session.setJdbcBatchSize(batchsize);

 for (int i = 0; i < n; i++) {
      Product p = new Product(i);
      super.persist(p);

      // Flush a batch of inserts and release memory
      if (i % session.getJdbcBatchSize() == 0 && i > 0) {
          getEntityManager().flush();
          getEntityManager().clear();
      }
  }

 }

Note: Setting session-level batching will override the value of hibernate.jdbc.batch_size if it is set. Nevertheless, if you want to globally set the batch size then it is recommended to use the hibernate.jdbc.batch_size.

The complete example is here.

marți, 26 iulie 2016

Hibernate batch processing with JpaRepository, JpaContext and PersistenceContext

As you can learn from How to batch INSERT and UPDATE statements with Hibernate (by Vlad Mihalcea), by default, Hibernate doesn't have the batch feature active. In order to activate it, just configure the hibernate.jdbc.batch_size property (e.g. between 5 and 30) as in the above article. For example, you can configure it depending on dialect bach size like this:

public static int batchSize() {
 return Integer.valueOf(Dialect.DEFAULT_BATCH_SIZE);
}

properties.put("hibernate.jdbc.batch_size", String.valueOf(batchSize()));  

Now, let's see three examples of Spring 4 MVC approaches that uses Hibernate batch for some inserts:

- Using JpaRepository:

public interface ProductRepository extends JpaRepository<Product, Long> {
 // NOPE
}

And ...

@Autowired
private ProductRepository productRepository;
...
@Override      
@Transactional
public void withBatching(int n) {

 // preparing the products
 ArrayList<Product> productsInBatch = new ArrayList<>();
 for (int i = 0; i < n; i++) {
      Product p = new Product(i);
      productsInBatch.add(p);
 }                

 long start = System.nanoTime();

 // persist via batching
 productRepository.save(productsInBatch);

 LOG.log(Level.INFO, "INSERTED {0} PRODUCTS IN: {1} MILISECONDS.",
         new Object[]{n, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)});        
}

The complete example is available here.

- Using JpaContext:

@Autowired
private JpaContext jpaContext;
...
@Override
@Transactional
public void withBatching(int n) {

 EntityManager em = jpaContext.getEntityManagerByManagedType(Product.class);

 long start = System.nanoTime();
 int batchSize = ...;

 // persist via batching        
 for (int i = 0; i < n; i++) {
      Product p = new Product(i);
      em.persist(p);

      // Flush a batch of inserts and release memory
      if (i % batchSize == 0 && i > 0) {
          em.flush();
          em.clear();
      }
  }
  
  LOG.log(Level.INFO, "INSERTED {0} PRODUCTS IN: {1} MILISECONDS.",
          new Object[]{n, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)});
}

The complete example is available here.

- Using PersistenceContext:

@PersistenceContext
private EntityManager entityManager;

And ...
@Autowired
private ProductDAO productDAO;

 @Override
 @Transactional
 public void withBatching(int n) {

  long start = System.nanoTime();

  // persist via batching    
  productDAO.persistWithBatching(n);

  LOG.log(Level.INFO, "INSERTED {0} PRODUCTS IN: {1} MILISECONDS.",
          new Object[]{n, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)});
}

The complete example is available here.

For a batch size of 15, in all examples you should get an output as below:

duminică, 24 iulie 2016

Asserting the SQL statement count generated by Hibernate JPA via a Spring 4 MVC example

Before reading this post is strongly recommended to read How to assert the SQL statement count generated by Hibernate by Vlad Mihalcea.

The steps needed to assert the SQL statement count generated by Hibernate are:

1. Configure the DataSource-Proxy (this is needed because it will proxy your data source and can obtain important info such as the bind parameters values and number of executed SQLs).
2. Add the countQuery() when you build the proxy in order to instruct DataSource-Proxy to create a DataSourceQueryCountListener. This provides metrics information per HTTP request such as datasource name, number of database call, total query execution time and number of queries by type

@Bean
public DataSource dataSource() {
 SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
 loggingListener.setQueryLogEntryCreator(new DefaultQueryLogEntryCreator());
 return ProxyDataSourceBuilder
        .create(actualDataSource())
        .name(DATA_SOURCE_PROXY_NAME)
        .listener(loggingListener)
        .countQuery()
        .build();
}

3. Use the QueryCount directly, or even better use the db-util provided by Vlad Mihalcea. Among other things, here we have access to an out-of-the-box automated validator named, SQLStatementCountValidatorThis validator comes with the following static assertions: assertSelectCount(), assertInsertCount(), assertUpdateCount() and assertDeleteCount(). Simply place in your POM the following dependency:

<dependency>
 <groupId>com.vladmihalcea</groupId>
 <artifactId>db-util</artifactId>
 <version>0.0.1</version>
</dependency>

4. In order to use this validator simply reset the QueryCount, execute the SQL statements and apply the proper assertions. Most likely, you will do this from an unit test, but just a quick sample we did it as below:

@Override  
@Transactional
public void storeProducts() {
       
 Product p1 = new Product();
 p1.setIdproducts(1);
 p1.setName("TV");
 p1.setCode("001");

 Product p2 = new Product();
 p2.setIdproducts(2);
 p2.setName("Microphone");
 p2.setCode("002");

 Product p3 = new Product();
 p3.setIdproducts(3);
 p3.setName("Phone");
 p3.setCode("003");
        
 SQLStatementCountValidator.reset();
      
 productRepository.save(p1);
 productRepository.save(p2);
 productRepository.save(p3);
     
 assertInsertCount(1);

}

If the number of expected SQLs differs from the number of executed SQLs then the SQLStatementCountValidator will throw an excpetion of type SQLFooCountMismatchException where Foo is one of Select, Insert, Update, Delete depending on the SQL type. For example, if we test with:

assertInsertCount(1);

then the message will be as:

com.vladmihalcea.sql.exception.SQLInsertCountMismatchException:

Expected 1 statements but recorded 0 instead!  

NOTE: This was just a proof of concept being practically a pretty dummy example. In reality, you can use the assertion of the SQL statement count generated by Hibernate to see what happens behind fetching and finding the N+1 issues as the example created by Vlad Mihalcea here.

The complete application based on Hibernate JPA and Spring 4 MVC can be found here. The example should failed because we have inserted three records and asserted for 1.

sâmbătă, 23 iulie 2016

Hibernate logging with DataSource-proxy via Hibernate JPA + Spring 4 MVC (Spring Data)

Before reading this post is strongly recommended to read The best way of logging JDBC statements by Vlad Mihalcea.

This is a sample application that shows how to use the DataSource-proxy to log the SQL statements with the bind parameter values. In three simple images, the application will do this:

1. Run it:


2. Press the button and check the database (is a MySQL database):


3. Check the server log and the /output.log file:


Done! The complete application is here.

luni, 11 iulie 2016

Data table pagination via PrimeNG + Spring MVC 4 RESTful web service + Hibernate JPA

Application output:

Simple database to provide data (database name: myproducts, table: products):

The complete example is available here.