Michael Z
Michael Z

Reputation: 3993

Commit during transaction in @Transactional

Is that possible to perform commit in the method that is marked as Spring's @Transactional?

@PersistenceContext
private EntityManager em;

@Transactional(propagation = Propagation.REQUIRED)
public void saveMembersWithMultipleCommits(List<Member> members)
    throws HibernateException
{
    Iterator<Member> it = members.iterator();
    while (it.hasNext())
    {
        while (it.hasNext())
        {
            Member wsBean = it.next();
            em.persist(wsBean); // overall commit will be made after method exit
            log.info("Webservices record " + wsBean + " saved. " + i++);
        }
    }
}

I would like to have commit to DB after say each 500 items. Is that possible with aforementioned context?

Upvotes: 5

Views: 31168

Answers (4)

vsingh
vsingh

Reputation: 6759

Alternate strategy is you create a method in DAO and mark it @Transactional. This method will do bulk update(for eg 500 nos). So you can have a method with code

@Transactional

public void mybatchUpdateMethod(){

    StatelessSession session = this.hibernateTemplate.getSessionFactory()
            .openStatelessSession();

    Transaction transaction = null;

    Long entryCounter = 0L;

    PreparedStatement batchUpdate = null;
    try {
        transaction = session.beginTransaction();
        batchUpdate = session.connection().prepareStatement(insertSql);

        for (BatchSnapshotEntry entry : entries) {
            entry.addEntry(batchUpdate);
            batchUpdate.addBatch();

            if (++entryCounter == 500) {
                // Reached limit for uncommitted entries, so commit
                batchUpdate.executeBatch();
            }
        }

        batchUpdate.executeBatch();
        batchUpdate.close();
        batchUpdate = null;
    }
    catch (HibernateException ex) {
        transaction.rollback();
        transaction = null;
    }
}

Every time you call this method, it will commit after 500 inserts/updates

Upvotes: -2

pap
pap

Reputation: 27614

No, you need to do it programatically using, for instance, the TransactionTemplate API. Read more here.

It would look something like

while (it.hasNext())
{
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            int counter = 0;
            while (it.hasNext() && counter++ < 500) {
                Member wsBean = it.next();
                em.persist(wsBean);
                log.info("Webservices record " + wsBean + " saved. " + i++);
            }
        }
    );
}

Upvotes: 5

Matin Kh
Matin Kh

Reputation: 5178

If you are looking forward to committing transactionally inside your other transaction, you might need to use @Transactional (propagation = Propagation.REQUIRES_NEW)

Upvotes: 2

Alex Barnes
Alex Barnes

Reputation: 7218

Your question suggests that you have misplaced your transaction boundary.

You can move the persist call into a private method and make that method transactional instead of the outer one. This method could accept 500 members at a time and then will commit when it exits.

Upvotes: 5

Related Questions