Я использую Spring Boot (1.4.4.REALEASE) с данными Spring, чтобы управлять базой данных MySql. У меня есть следующий случай:Весенний родной запрос, выполненный в транзакции, принимающей устаревшее значение
- Мы обновляем одну ревизию, выполненную на одном оборудовании, с использованием
RevisionService
. RevisionService
сохраняет изменения и вызываетEquipmentService
для обновления состояния оборудования.- UpdateEquipmentStatus выполняет вызов хранимой процедуры Db, чтобы оценить оборудование с его пересмотрами в целом и обновить поле.
Я пробовал некоторые варианты, но не добился того, чтобы получить обновленный статус для оборудования. Метод updateEquipmentStatus
продолжает записывать предыдущий статус для оборудования (не учитывая текущую ревизию, хранящуюся в транзакции). Код написан так:
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);
}
Насколько я понимаю, поскольку оба метода аннотируются транзакцией Spring, метод updateEquipmentStatus
должен выполняться в рамках текущей транзакции. Я также пробовал с различными вариантами для аннотации @Transactional
от updateEquipmentStatus
, таких как @Transactional(isolation=Isolation.READ_UNCOMMITTED)
(что не должно требоваться, потому что я использую ту же транзакцию) и @Transactional(propagation=Propagation.REQUIRES_NEW)
, но не рассматривает текущий статус. Вот как моя хранимая процедура сохраняются в БД MySql:
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
Я также хочу уточнить, что если я выполняю некоторые изменения в самом оборудовании (которое влияет только Tequipment), то статус должным образом обновляются. InnoDb - это двигатель, используемый для всех таблиц.
UPDATE
Просто изменил метод прямого РЕПО использовать nativeQuery, а и та же проблема продолжает происходит, поэтому процедура Db вовлечения должны быть отброшены:
@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
UPDATE2
Сделав несколько тестов и добавил журнал с TransactionSynchronizationManager.getCurrentTransactionName()
в методах, что это конкретный вопрос:
- Изменения, сделанные в службе оборудования правильно подобраны функции обновления (Когда-то в изменении Tequipment, статус в расходование рассчитывается должным образом).
- Изменения, внесенные в службу ревизии (trevision), приводят к устаревшему значению в тексте (не имеет значения, использует ли Spring его в другой транзакции с использованием REQUIRES_NEW или нет). Spring, похоже, правильно создает новую транзакцию при использовании REQUIRES_NEW в
establishEquipmentStatus
, потому что текущее имя транзакции изменяется, но собственный запрос не имеет последних значений (из-за транзакции до того, как она не была совершена?). Также попытался удалить@Transactional
сestablishEquipmentStatus
, поэтому используется та же транзакция, но проблема продолжает происходить. - Я хочу, чтобы выделил, что запрос, используемый для обновления состояния оборудования, имеет case expression с несколькими подзапросами, использующими trevision.
Привет, жаль задержка. На самом деле проблема не хранится - процедура специфична, но кажется, что она больше связана со многими таблицами, участвующими в одной и той же транзакции (она принимает значения старой таблицы). Более или менее это поток выполнения: 1. Обновите версию, используя Hibernate. 2. Выполните метод updateEquipmentStatus, который запускает модификацию собственного запроса (этот запрос использует некоторые данные, участвующие в шаге 1, который устарел). –