我正在使用Spring Boot(1.4.4.REALEASE)和Spring Data来管理MySql数据库。我有以下案例:
RevisionService
更新在一台设备中执行的一次修订。RevisionService
保存修订版并调用EquipmentService
更新设备状态。我尝试了一些选项,但没有达到获取设备的更新状态。 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)
(这不应该是必需的,因为我使用相同的事务)和{{ 1}},但不考虑当前状态。这就是我的存储过程保存到MySql DB的方式:
@Transactional(propagation=Propagation.REQUIRES_NEW)
我还想澄清一下,如果我在设备本身中执行一些修改(仅影响设备),则状态正在正确更新。 InnoDb是用于所有表格的引擎。
更新
刚刚更改了repo方法以使用nativeQuery而且同样的问题一直在发生,因此涉及的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
UPDATE2
在方法中完成了更多测试并添加了TransactionSynchronizationManager.getCurrentTransactionName()
的日志,这就是具体问题:
@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);
中使用REQUIRES_NEW时似乎正确创建了一个新事务,因为当前事务名称更改,但本机查询没有最新值(因为事务未被提交之前?)。还尝试从establishEquipmentStatus
删除@Transactional
,因此使用相同的交易,但问题仍然存在。答案 0 :(得分:0)
更改为读取未提交是正确的想法,但您还需要在调用存储过程之前刷新实体管理器。见这个主题:
How to make the queries in a stored procedure aware of the Spring Transaction?
除非你绝对被迫使用存储过程,否则我会在Spring中完成所有工作。
答案 1 :(得分:0)
添加以下代码可以修复它(以编程方式将事务状态刷新到数据库):
@Service
public class EquipmentService{
@PersistenceContext
private EntityManager entityManager;
@org.springframework.transaction.annotation.Transactional
public Long updateEquipmentStatus(Long idEquipment){
entityManager.flush();
repo.updateEquipmentStatus(idEquipment);
}
}
找到一种声明性的方式来做它仍然会很棒..