Nakesh
Nakesh

Reputation: 576

How to force commit entity in @Transactional mode

I am using Spring data jpa and jdbc (using entityManager.unwrap(Session.class) ) connection.
My request flows through 3 method. 1st -> 2nd ->3rd.
1st and 3rd are annotated with @Transactional.
In 1st and 2nd method saving entity through JPA CRUD repository.
In 3rd method using basic jdbc query to retrieve values saved in 2nd method.
As we know in @Transaction entities are not committed to database until JPA commit the transaction.
I used saveAndFlush also in 2nd method but can not see retrieve updated values in method 3 using jdbc query.

1st Method - update()

@Transactional
@Override
public ApiResponse update(RequestInput input) {
    ApiResponse response = doRestOfWork(input);   // calling 2nd method
    // .... some other entity save....
}

2nd Method - doRestOfWork() : setting status=true and calling saveAndFlush method

@Override
public ApiResponse doRestOfWork(Request request) {
    Insight insight = insightRepository.findOne(request.getTypeId());
    insight.setStatus(true);
    insightRepository.saveAndFlush(insight);

    processOperation();    // calling 3rd method
}

3rd method - processOperation() : retrieving updated status value through jdbc connection.

@Transactional
public void processOperation() {
Connection conn = null;
        SessionImplementor sessionImpl = (SessionImplementor) entityManager.unwrap(Session.class);
        try {
            conn = sessionImpl.getJdbcConnectionAccess().obtainConnection();
            Connection conn = null;
            String stmt = "SELECT status from insight";
            PreparedStatement ps = conn.prepareStatement(stmt);
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
               boolean value = rs.getBoolean(status);   // returning false, i want this to return true as already set true in 2nd method and called saveAndFlush 
        }
    } catch (SQLException ex) {
    } finally {
        JdbcUtility.closeResources(conn, ps, rs);
    }
}

InsightRepository is extending JpaRepository

@Repository
public interface InsightRepository extends JpaRepository<Insight, Long> {}

I want updated value of status (which is boolean true - updated in method 2) in method 3. How to achieve this ?

Update

I searched a lot and do not think that if a method is annotated with @Transactional then you can commit changes before completing JPA transaction. So the solution is to remove @Transactional annotation and use entityManager.getTransaction() if want to control over JPA transaction.

Upvotes: 1

Views: 22573

Answers (2)

Arif Ulusoy
Arif Ulusoy

Reputation: 244

Create a method (4th method) for update with @Transactional(propagation = Propagation.REQUIRES_NEW) annotation in a bean different from the 2nd Method and change second method as calling 4th method like this :

@Component //or Service etc..
public class AnotherBean{

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void doUpdateWork(Request request){
    Insight insight = insightRepository.findOne(request.getTypeId());
    insight.setStatus(true);
    insightRepository.save(insight);
  }
} 

and

    @Override
    public ApiResponse doRestOfWork(Request request) {
        anotherBean.doUpdateWork(request);
        processOperation();    // calling 3rd method
    }

Upvotes: 3

Antoniossss
Antoniossss

Reputation: 32507

If you want to controll transaction, dont use @Transactional

em; //entityManager

Transaction tx=em.getTransaction();
try{
   tx.begin();
   //do work
   tx.commit(); // comminted transaction 
 // start another transaction if you need to, doo more work etc.
...
}

This is most basic and fundamental block of code for using JPA for atomic operations.

Also there is no need to unwrap entity manager, use pure JPA. By unwrapping you are binding current implementation to JPA provider which is in contrary to JPA idea of independency from underlying JPA implementation provider. In other words, it will stop working if for some reasons Spring would change its JPA implementation from Hibrnate to eg. EclipseLink.

Upvotes: 0

Related Questions