programing

오래된 값을 사용하는 트랜잭션 내에서 실행되는 스프링 네이티브 쿼리

skycolor 2023. 7. 21. 21:30
반응형

오래된 값을 사용하는 트랜잭션 내에서 실행되는 스프링 네이티브 쿼리

Spring Boot(1.4.4)를 사용하고 있습니다.REALEASE)를 사용하여 MySql 데이터베이스를 관리합니다.다음과 같은 사건을 맡았습니다.

  1. 다음을 사용하여 하나의 장비에서 수행된 하나의 개정판을 업데이트합니다.RevisionService.
  2. RevisionService하고 "" " " " 를 합니다.EquipmentService장비 상태를 업데이트합니다.
  3. 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);

}

모두알고 , 제 이 해 하 스 모 거 프 주 의 달 때 이 문 에 렸 기 석 에 래 링 가 두 기 법 두 방 로 는 ▁as 때 , 에 문 ▁are ▁as ▁methods ▁the ▁with 제updateEquipmentStatus메서드는 현재 트랜잭션의 범위에서 실행되어야 합니다.저는 또한 다양한 옵션을 사용하여 시도했습니다.@Transactional의 주석updateEquipmentStatus를 들어, 를들어예와 같은@Transactional(isolation=Isolation.READ_UNCOMMITTED).) 및 (같은트랜션사있필때않지요습하다니문에기용고을하잭)▁(않다습니▁(같▁shouldn)@Transactional(propagation=Propagation.REQUIRES_NEW)하지만 계속해서 현재 상태를 고려하지 않고 있습니다. DB 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

또한 장비 자체에서 일부 수정을 실행하면(장비에만 영향을 미치는) 상태가 제대로 업데이트되고 있음을 명확히 하고 싶습니다.InnoDb는 모든 테이블에 사용되는 엔진입니다.


갱신하다

nativeQuery를 대신 사용하도록 repo 방법을 변경했는데 동일한 문제가 계속 발생하므로 관련된 DB 절차를 폐기해야 합니다.

@Modifying
@Query(nativeQuery = true, value= "update tequipment set equipment_status = (CASE WHEN (...))")
void updateEquipmentStatus(@Param("id_param") Long idEquipment);

업데이트 2

더 많은 테스트를 수행하고 방법 내에 로그를 추가한 것이 구체적인 문제입니다.

  • 장비 서비스에서 수행된 변경 사항은 업데이트 기능에 의해 적절히 선택됩니다(장비가 변경되면 상태 장비가 올바르게 계산됨).
  • 리비전 서비스(리비전)에서 변경하면 오래된 값 장비가 됩니다(스프링이 REQUESTES_NEW를 사용하여 다른 트랜잭션에서 이를 수행하는지 여부는 중요하지 않습니다).은 REQUESTS_NEW에서 할 때 하는 것 .establishEquipmentStatus현재 트랜잭션 이름은 변경되지만 네이티브 쿼리에 최신 값이 없기 때문입니다(커밋되지 않은 트랜잭션 때문에?).제거도 시도했습니다.@Transactional부터establishEquipmentStatus동일한 거래가 사용되지만 문제가 계속 발생합니다.
  • 장비 상태를 업데이트하는 데 사용되는 쿼리에는 trevision을 사용하는 여러 하위 쿼리가 포함된 사례 표현식이 있음을 강조하고 싶습니다.

다음 코드를 추가하면 수정됩니다(데이터베이스로 트랜잭션 상태를 프로그래밍 방식으로 플러시).

@Service
public class EquipmentService{

    @PersistenceContext
    private EntityManager entityManager;

    @org.springframework.transaction.annotation.Transactional
    public Long updateEquipmentStatus(Long idEquipment){
        entityManager.flush();
        repo.updateEquipmentStatus(idEquipment);
    }
}

그래도 선언적인 방법을 찾는 것은 좋을 것입니다.

읽기를 커밋되지 않음으로 변경하는 것은 올바른 생각이지만 저장 프로시저를 호출하기 전에 엔티티 관리자를 플러시해야 합니다.다음 스레드 참조:

저장 프로시저의 쿼리에 스프링 트랜잭션을 인식시키는 방법은 무엇입니까?

개인적으로 당신이 저장 프로시저를 사용하도록 절대적으로 강요하지 않는 한 저는 봄에 모든 것을 할 것입니다.

언급URL : https://stackoverflow.com/questions/42294469/spring-native-query-executed-within-a-transaction-taking-outdated-value

반응형