我正在使用Sping Boot (1.4.4.REALEASE)和Spring Data来管理MySql数据库。我有以下案例:
1.我们使用RevisionService
更新在一台设备中执行的一次修订。
RevisionService
保存修订版并调用EquipmentService
更新设备状态。- updateEquipmentStatus调用一个Db存储过程,以评估设备及其修订版本并更新字段。
我已经尝试了一些选项,但无法获得设备的更新状态。updateEquipmentStatus
方法继续写入设备的以前状态(不考虑当前版本存储在事务中)。代码是这样写的:
修订服务
@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);
}
}
字符串
设备服务
@Service
public class EquipmentService{
@org.springframework.transaction.annotation.Transactional
public Long updateEquipmentStatus(Long idEquipment){
repo.updateEquipmentStatus(idEquipment);
}
}
型
设备回购
@Repository
public interface EquipmentRepo extends CrudRepository<Equipment, Long> {
@Modifying
@Procedure(name = "pupdate_equipment_status")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
}
型
据我所知,由于这两个方法都使用Spring的transactional进行了注解,因此updateEquipmentStatus
方法应该在当前transaction的范围内执行。(这不应该是必需的,因为我使用的是同一个事务)和@Transactional(propagation=Propagation.REQUIRES_NEW)
,但一直不考虑当前状态。这就是我的存储过程保存到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
型
我还想澄清的是,如果我对设备本身进行了一些修改(这只会影响tequipment),状态会被正确更新。InnoDb是用于所有表的引擎。
更新
只是将repo方法改为使用nativeQuery,同样的问题一直在发生,所以应该放弃所涉及的Db过程:
@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
型
- 酒店
在做了更多的测试并在方法中添加了一个带有TransactionSynchronizationManager.getCurrentTransactionName()
的日志之后,这就是具体的问题:
- 设备服务中的更改由更新功能正确选择(当设备中的某些内容发生更改时,设备中的状态将正确计算)。
- 在修订版服务中完成的更改导致设备价值过时(Spring是否在不同的transaction中使用REQUIRES_NEW并不重要)。Spring在
establishEquipmentStatus
中使用REQUIRES_NEW时似乎正确地创建了一个新transaction,因为当前transaction名称更改,但本机查询没有最新值(因为没有提交之前的事务?).还尝试从establishEquipmentStatus
中删除@Transactional
,以便使用相同的事务,但问题一直发生。 - 我想强调的是,用于更新设备状态的查询有一个case expression,使用trevision有多个子查询。
3条答案
按热度按时间cedebl8k1#
添加以下代码可以修复此问题(将事务状态自动刷新到数据库):
字符串
不过,如果能找到一种声明性的方式来做这件事,那就太好了。
lnxxn5zx2#
修改为read uncommitted是正确的想法,但在调用存储过程之前,您还需要刷新entitymanager。请参阅以下线程:
How to make the queries in a stored procedure aware of the Spring Transaction?
就我个人而言,我会在Spring中完成这一切,除非你绝对必须使用存储过程。
pjngdqdw3#
字符串
这对我来说很有效,这个注解更新了持久化上下文。我注意到,如果我调用调用过程的方法,因为它是一个事务,持久化上下文将不会更新,直到方法终止。
https://www.baeldung.com/spring-data-jpa-modifying-annotation