Search code examples
spring-bootspring-dataspring-jdbcjdbctemplate

Spring-data JdbcTemplate does not commit


I need to update thousands of records in the database but i would like to commit after a batch of 5000 records.

@Service
@Transactional (rollbackFor=Throwable.class)
public class AttributeProcessorServiceImpl extends DataLoader implements 
                  AttributeProcessorService
{
    .....
    private final TransactionTemplate transTemplate;
    private final JdbcTemplate jdbcTemplate;
    @Autowired private PlatformTransactionManager platformTransactionManager;

    @Autowired
    public BlockAttributeProcessorServiceImpl( 
        TransactionTemplate transTemplate,
        JdbcTemplate jdbcTemplate,
        .....)
    {
        super();
        this.transTemplate = transTemplate;
        this.jdbcTemplate=jdbcTemplate;
        .....
    }

    @Async
    @Transactional (propagation=Propagation.NOT_SUPPORTED)
    public void reloadAttrs()
    {
        loadAttrs();
        updateAttrs();
    }

    private void loadAttrs()
    {
         ...some data fetching and processing, finally call db update.
         updateDbInBatches(rowcount, sql);
    }

    private void updateAttrs()
    {
         ...some data fetching and processing, finally call db update.
         updateDbInBatches(rowcount, sql);
    }

    private void updateDbInBatches(long rowcount, String sql)
    {
        DefaultTransactionDefinition def;
        boolean hasMore=true;
        Integer from;
        Integer to = 0;
        int batchSize=5000; //gets from property

        while (hasMore)
        {
            from = to+1;
            to = batchSize;

            def = new DefaultTransactionDefinition();
            def.setName("backCommitTx");
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            TransactionStatus status = platformTransactionManager.getTransaction(def);
  
            int rows = jdbcTemplate.update(sql,paramValues,paramTypes);
            logger.debug("Loaded ["+rows+"] records.");
            platformTransactionManager.commit(status);

            if (to > rowcount)
            {
                hasMore=false;
                logger.debug("All records ["+rowcount+"] updated.");
            }
        }
    }
}

If I put a breakpoint after loadAttrs(), it shows it loaded bunch of records to the database and issued a commit(), but database does not reflect that commit, until after entire public method completes. How do i ensure data is indeed written to the database after each commit. commit neither gives any error as well.


Solution

  • I missed an important piece of information that solved the problem.

    I had another public method which is what was called from outside.

    public void reloadAttrs(TransDetail trans)
    {
        reloadAttrs();
    }
    

    Above method was infact using default Transaction Propagation as i did not mention it specifically. Since this was the first public method that was called, spring was ignoring transaction demarcation on next public (async) method that was called. I changed above signature to:

    @Transactional (propagation=Propagation.NOT_SUPPORTED)
    public void reloadAttrs(TransDetail trans)
    {
        reloadAttrs();
    }
    

    It then worked. I was able to see changes in the database after every commit.