2011-09-15 4 views
0

이 시나리오를 캡처 할 핵심 단어가 없기 때문에 설명해 보겠습니다. 수업은 단순화되었습니다.POJO DTO의 JPA 동기화/커밋 오류 (저장하지 않으려는 경우)

이 감안할 : 예외가 discountService.hasDiscount 던져

public ItemController { 
    @Autowired 
    ItemDtoService ItemDtoService; 

    @Autowired 
    DiscountService discountService; 
    @RequestMapping(value = "/viewItems", method = RequestMethod.POST) 
    public void process() { 
     List<ItemDto> ItemDtos = ItemDtoService.getItemDtos(); 
     for(ItemDto i: ItemDtos) { 
      boolean isDiscounted = discountService.hasDiscount(i); //throws exception here on iteration 2 and the last iteration, ItemDto was discounted 
      if (isDiscounted) { 
       i.setPrice(discountService.getDiscountedPrice(i)); 
       //do some other i.setter, basically modify the pojo 
      } 
     }   
    } 
} 

: 이후 반복

  • 및 이전 반복에

    1. 는 ItemDto이 할인되었습니다.

    예외는 다음과 같습니다

    Caused by: org.hibernate.exception.SQLGrammarException: could not update: [somepackage.ItemDto#364] 
    

    그리고 어딘가에 스택 트레이스에이 표시됩니다

    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:456)" 
    

    문제는 그 메소드 호출입니다 즉 @Transactional입니다 밑에 DAO 방식을 사용 (그리고 아마도 그것은 단지 쿼리, 복잡한 쿼리 임에도 불구하고 좋은 이유로). JPA Tx 관리자가 메소드 호출 종료시 작업을 수행하면 pojo가 수정 된 것으로보고 동기화하려고 시도합니다. ItemDtoService.getItemDtos 안에는 getEntityManager(). createNativeQuery (nativeSql, ItemDto.class)가 사용되므로 ItemDto pojo에는 @Entity가 있습니다. 기타 5 가지 세부 정보는 다음과 같습니다.

    @Entity 
    public class ItemDto{ 
        //body 
    } 
    
    
    @Service 
    public class ItemService { 
        @Autowired 
        ItemDao itemDao; 
    
        public List<ItemDto> getItems() { 
         return itemDao.getItems(); //for sake of simplicity  
        } 
    } 
    
    @Repository 
    @Transactional 
    public class ItemDaoImpl { 
        public List<ItemDto> getItems() {  
         String nativeSql = "select...." 
         return getEntityManager().createNativeQuery(nativeSql, ItemDto.class);  
        } 
    
    } 
    
    @Service 
    public class DiscountService { 
        @Autowired 
        DiscountDao discountDao; 
    
        public boolean hasDiscount(ItemDto i) {  
         boolean hasDiscount = discountDao.hasDiscount(i); 
         //do other service stuff that might influence the hasDiscount flag 
         return hasDiscount;  
        } 
    } 
    
    @Repository 
    @Transactional 
    public class DiscountDaoImpl { 
        public boolean hasDiscount(ItemDto i) {  
         String nativeSql = "select...." 
         boolean hasDiscount; 
         //in reality the query is a complicated joins, executes and returns if has discount or not 
         return hasDiscount; 
        } 
    
    } 
    

    내가 뭘 잘못하고 있니?

    내가 노력하고 일한 옵션 중 일부

    은 다음과 같습니다 : 그들은 단지 쿼리 (사람들은 수 있습니다 부정적인 영향이 생각입니다 때문에

    1. 가 다오 방법 에 @Transactional 제 (읽기 전용 = True)로 추가 의도적 복잡한 쿼리 때문에에는 트랜잭션 및 그것이 다음 할인되는 아이템 보는 통해 반복 2 개 루프 1이 상기 제어부에서
    2. ) 더티 판독 방지 변경을위한 별도의 루프를 생성하는 록킹을해야 할 수도 그 정보를 어딘가에 저장하십시오. 않는, 2 루프 나중에 참조 할 수의 변경은 POJO를

    내가 다른 옵션을보고, 당신이 그것을 코딩 된 방법에 문제가 표시되는 경우 의견을주십시오하고있다. 목록 어쨌든 DTO 때문에

    getEntityManager().clear(); 
    

    그것은 잘 작동 하나는 기대 :

  • 답변

    0
    난 그냥 발견하는 또 다른 옵션은 ItemDto의 목록을 반환 다오 안에

    는 목록을 반환하기 전에, 나는 이것을 실행하는 것 이들은 DB 동기화를 필요로하지 않으며 동시에 @Transactional은 일관된 읽기를 위해 필요한 잠금을 위해 유지됩니다.

    이것은 하나 이상의 대안이지만, 실제로 가장 적합한 방법은 무엇입니까?