A customer of mine has a highly scalable system, with high database load. To improve performance, we’ve decided to use Batch update. Alas – the application uses JPA, so how do we do it?
SessionFactoryImplementor sfi = SessionFactoryImplementor)entityManager.unwrap(Session.class).getSessionFactory(); //Retrieve DB connection connect = sfi.getConnectionProvider().getConnection(); PreparedStatement ps = connect.prepareStatement("INSERT INTO temp_table values(?,?)"); for (Data p : insertCommands) { ps.setInt(1, p.getId()); if (p.isWorking() != null) { ps.setInt(2, p.isWorking() ? 1 : 0); } else { ps.setNull(2, Types.INTEGER); } ps.addBatch(); } ps.executeBatch();
Some points to remember:
- Do not close the connection!!! When closing the connection, it returns to the connection pool, without commit or rollback. You’ll get some exceptions in your code, but mainly – you’re open to database locks and dead-locks, as the connection keeps all the locks that were done in the batch update. And since other threads will reuse the connection – it will never close.
- Do not use Statement.addBatch. Use PreparedStatement.addBatch. When I checked both solutions, the Statement one took anywhere between 30s-60s. The PreparedStatement version took <300ms…