2011-09-15 6 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. は、彼らが唯一のクエリなので(負の効果はしかし、それらは あるかもしれないですDaoのメソッド 上(読み取り専用=真)@Transactionalに追加します故意による複雑なクエリへのトランザクション、及びダーティ・リード防止する ロックを必要とするかもしれない)コントローラで
    2. 、修飾のための別個のループを作成し、それは 次いで が割り引かれるアイテムとシーイングをループするための2つのループ、1を持っています、それらの情報をどこかに保存する言ったのPOJOの修正

    を行う第二 ループ、上、後で参照する私は他のオプションを見て、あなたはそれがコード化された方法と間違って何かを見たらコメントしてくださいしています。私はちょうど見つけ

  • 答えて

    0

    別のオプションは、リストを返す前に、私はこれを実行するだろう、ItemDtoのリストを返すダオ内にある:

    getEntityManager().clear(); 
    

    リストはDTOあるので、それはとにかく正常に動作し、もう1つは期待しますこれらはDB同期を必要としないと同時に、一貫性のある読み取りのために必要なロックのために@Transactionalが保持されます。

    もう1つの選択肢ですが、実際には最も適切な方法は何ですか?

    関連する問題