Reputation: 576
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
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
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