I'm using Spring Boot (1.4.4.REALEASE) with Spring Data in order to manage a MySql Database. I've got the following case:
- We update one revision performed in one equipment using the
RevisionService
. RevisionService
saves the revision and calls theEquipmentService
to update the equipment status.- The updateEquipmentStatus does a call to a Db stored procedure in order to evaluate the equipment with its revisions altogether and update the field.
I've tried some options but don't achieve to get the updated status for the equipment. The updateEquipmentStatus
method keeps writing the previous status for the equipment (not considering the current revision being stored in the transaction). The code is written this way:
RevisionService
@Service
public class RevisionService{
@org.springframework.transaction.annotation.Transactional
public Long saveRevision(Revision rev){
//save the revision using JPA-Hibernate
repo.save(rev);
equipmentService.updateEquipmentStatus(idEquipment);
}
}
EquipmentService
@Service
public class EquipmentService{
@org.springframework.transaction.annotation.Transactional
public Long updateEquipmentStatus(Long idEquipment){
repo.updateEquipmentStatus(idEquipment);
}
}
EquipmentRepo
@Repository
public interface EquipmentRepo extends CrudRepository<Equipment, Long> {
@Modifying
@Procedure(name = "pupdate_equipment_status")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
}
As far as I understand, as both methods are annotated with Spring's transactional, the updateEquipmentStatus
method should be executed in the scope of the current transaction. I've also tried with different options for the @Transactional
annotation from updateEquipmentStatus
, such as @Transactional(isolation=Isolation.READ_UNCOMMITTED)
(which shouldn't be required, because I'm using the same transaction) and @Transactional(propagation=Propagation.REQUIRES_NEW)
, but keeps not considering the current status. That's how my stored procedure is saved into the MySql DB:
CREATE DEFINER=`root`@`localhost` PROCEDURE `pupdate_equipment_status`(IN `id_param` INT)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
/*Performs the update considering tequipment and trevision*/
/*to calculate the equipment status, no transaction is managed here*/
END
I also want to clarify that if I execute some modification in the equipment itself (which affects only tequipment), the status is being properly updated. InnoDb is the engine being used for all the tables.
UPDATE
Just changed the repo method to use a nativeQuery instead and the same problem keeps happening, so the Db procedure being involved should be discarded:
@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
UPDATE2
Having done more tests and added a log with TransactionSynchronizationManager.getCurrentTransactionName()
in the methods, that's the concrete issue:
- Changes done in the equipment service are properly picked by the updating function (When something in tequipment changes, the status in tequipment is calculated properly).
- Changes done in the revision service (trevision) result in an outdated value in tequipment (it doesn't matter if Spring does it in a different transaction using REQUIRES_NEW or not). Spring seems to create a new transaction properly when using REQUIRES_NEW in
establishEquipmentStatus
, because the current transaction name changes, but the native query doesn't have the latest values (because of the transaction before not being commited?). Also tried removing@Transactional
fromestablishEquipmentStatus
so the same transaction is used, but the issue keeps happening. - I would like to highlight that the query used to update equipment status has a case expression with multiple subqueries using trevision.
updateEquipmentStatus
method, which fires a modifying native query (this query uses some data involved in the step 1, which is outdated). – Population