SqlReportEntitiesPersister implements EntityPersister { @Override @Transactional @Retryable( value = {LockAcquisitionException.class}, maxAttemptsExpression = "#{ @systemProperties['retryBackoff'] ?: 20}", backoff = @Backoff( delayExpression = "#{ @systemProperties['retryDelay'] ?: 100}", maxDelayExpression = "#{ @systemProperties['retryMaxDelay'] ?: 50000 }", multiplierExpression = "#{ @systemProperties['retryMultiplier'] ?: 1.5}")) public void persistReportEntities(List<? extends Report> reportEntities) { int batchFlush = 0; Session session = sessionFactory.getCurrentSession(); FlushMode previousFlushMode = session.getHibernateFlushMode(); session.setHibernateFlushMode(FlushMode.MANUAL); try { for (Report report : reportEntities) { report.setRowId(); session.saveOrUpdate(report); batchFlush++; if (batchFlush == config.getBatchSize()) { session.flush(); session.clear(); batchFlush = 0; } } if (batchFlush > 0) { session.flush(); session.clear(); } } catch (NonUniqueObjectException ex) { logger.error( "Duplicate row detected. This is most likely because your report definition does not " + "include the primary key fields defined in {}.setRowId(). " + "Please add the missing fields and try again.", reportEntities.get(0).getClass().getName()); throw ex; } finally { session.setHibernateFlushMode(previousFlushMode); } } @Autowired  SqlReportEntitiesPersister(SessionFactory sessionFactory, Config config); @Override @Transactional @Retryable( value = {LockAcquisitionException.class}, maxAttemptsExpression = "#{ @systemProperties['retryBackoff'] ?: 20}", backoff = @Backoff( delayExpression = "#{ @systemProperties['retryDelay'] ?: 100}", maxDelayExpression = "#{ @systemProperties['retryMaxDelay'] ?: 50000 }", multiplierExpression = "#{ @systemProperties['retryMultiplier'] ?: 1.5}")) void persistReportEntities(List<? extends Report> reportEntities); @Override @Transactional T save(T t); @SuppressWarnings("unchecked") @Override @Transactional(readOnly = true) List<T> get(Class<T> classT, String key, V value);  }
@Test public void persistReportEntities_savesSingleInstance() { AccountPerformanceReport report = generateReport(1); sqlEntitiesPersister.persistReportEntities(Arrays.asList(report)); sequence.verify(session).saveOrUpdate(report); }
@Test public void persistReportEntities_abortsOnSqlException() { Mockito.doThrow(new HibernateException("")).when(session).saveOrUpdate(any()); try { sqlEntitiesPersister.persistReportEntities(Arrays.asList(generateReport(1))); fail(); } catch (HibernateException ex) { } }
@Test public void persistReportEntities_retriesAfterDeadlockThenFails() { AccountPerformanceReport report = generateReport(1); Mockito.doThrow(new LockAcquisitionException("", null)).when(session).saveOrUpdate(any()); try { sqlEntitiesPersister.persistReportEntities(Arrays.asList(report)); fail(); } catch (LockAcquisitionException ex) { } sequence.verify(session, Mockito.times(20)).saveOrUpdate(report); }
@Test public void persistReportEntities_retriesAfterDeadlockThenSucceeds() { AccountPerformanceReport report = generateReport(1); Mockito.doThrow(new LockAcquisitionException("", null)) .doNothing() .when(session) .saveOrUpdate(any()); sqlEntitiesPersister.persistReportEntities(Arrays.asList(report)); sequence.verify(session, Mockito.times(2)).saveOrUpdate(report); }
@Test public void persistReportEntities_setsManualFlushModeAndResetsIt() { AccountPerformanceReport report = generateReport(1); Mockito.when(session.getHibernateFlushMode()).thenReturn(FlushMode.AUTO); sqlEntitiesPersister.persistReportEntities(Arrays.asList(report)); sequence.verify(session).getHibernateFlushMode(); sequence.verify(session).setHibernateFlushMode(FlushMode.MANUAL); sequence.verify(session).setHibernateFlushMode(FlushMode.AUTO); }