2013-09-30 36 views
1

我有以下具有1對N關係的Persistable類。一對多關係和序列化對象字段

@PersistenceCapable 
public class Pet { 

    @Persistent(primaryKey = "true", valueStrategy = IdGeneratorStrategy.IDENTITY) 
    Long id; 

    @Persistent 
    String name; 

    @Element(column = "PET_ID") 
    List<Photo> photos; 

    // getters and setters 

@PersistenceCapable 
public class Photo { 

    @Persistent(primaryKey = "true", valueStrategy = IdGeneratorStrategy.IDENTITY) 
    Long id; 

    @Persistent 
    String desc; 

    @Persistent(serialized="true") 
    Object image; 

    // getters and setters 

    // hash and equal using field id 

字段表照片使用FK建立寵物之間1-N的關係(1)和圖片(N)。字段對象圖像在Photo中是一個序列化的圖像對象。

對於數據存儲區操作我使用PetDao,這已下列方法

public final static PersistenceManagerFactory pmf = JDOHelper 
      .getPersistenceManagerFactory("datastore"); 

public void storePet(Pet pet) { 
    // get PM and current tx 
    try { 
     tx.begin(); 
     pm.makePersistent(pet); 
     tx.commit(); 
    } catch (Exception e) { 
     // rollback and close pm 
    }   
} 

public void storePhoto(Long petId, Photo photo) { 
    // get PM and current tx 
    try { 
     tx.begin(); 
     Pet pet = pm.getObjectById(Pet.class,petId); 
     pet.addPhoto(photo); 
     tx.commit(); 
    } catch (Exception e) { 
     // rollback and close pm 
    } 
} 

我創建和持久對象作爲

Pet pet = new Pet(); 
pet.setName("Nicky"); 

Photo photo = new Photo(); 
photo.setDesc("Photo 1"); 
photo.setImage(new Image("image 1")); 
pet.addPhoto(photo); 

.... add photo 2 and photo 3 

PetDao petDao = new PetDao();  
petDao.storePet(pet); 

// i have one more photo so add it directly 
photo = new Photo(); 
photo.setDesc("Photo 4"); 
photo.setImage(new Image ("image 4"));  

petDao.storePhoto((long)0, photo); 

一切仍然存在需要和數據存儲在PET表1個寵物結束和PHOTO表中的4張照片。

但是,當我分析的DataNucleus日誌爲petDao.storePhoto((long)0,photo)代碼,我看到DataNucleus從數據存儲中檢索所有圖像對象。

Native   [DEBUG] INSERT INTO PHOTO ("DESC",IMAGE,PET_ID,PHOTOS_INTEGER_IDX) VALUES (<'Photo 4'>,<UNPRINTABLE>,<0>,<3>) 
Persist   [DEBUG] Execution Time = 70 ms (number of rows = 1) on PreparedStatement "[email protected]6" 
Persist   [DEBUG] Object "[email protected]" was inserted in the datastore and was given strategy value of "3" 
Native   [DEBUG] SELECT A0.IMAGE FROM PHOTO A0 WHERE A0.ID = <1> 
Retrieve  [DEBUG] Execution Time = 1 ms 
Native   [DEBUG] SELECT A0.IMAGE FROM PHOTO A0 WHERE A0.ID = <0> 
Retrieve  [DEBUG] Execution Time = 0 ms 
Native   [DEBUG] SELECT A0.IMAGE FROM PHOTO A0 WHERE A0.ID = <2> 
Retrieve  [DEBUG] Execution Time = 0 ms 

添加了 「照片4」 使用INSERT INTO照片...語句之後,DataNucleus將通過發射3 SELECT映像從PHOTO語句檢索前面三個圖像對象。 隨着圖像對象數量的增加,這些檢索可能會相當大,從而導致數據存儲上不必要的負載影響性能。

如果我使用pm.getObjectById()選擇寵物,並分離寵物對象並將照片添加到分離的對象,然後用pm.makePersistent(pet)將其附加回對象圖,則會發生同樣的事情。 FetchGroup是如下

@PersistenceCapable(detachable="true") 
@FetchGroup(name="detachPhotos", members={@Persistent(name="photos")}) 
public class Pet { 
    .... 
} 

和分離的寵物fetchgroup

public Pet getPet(Long id){ 
    PersistenceManager pm = pmf.getPersistenceManager(); 
    pm.getFetchPlan().addGroup("detachPhotos"); 
    Pet pet = pm.getObjectById(Pet.class, id);  
    return pm.detachCopy(pet); 
} 

我的問題是如何避免從數據存儲器對象圖像的這些不必要的重試。

還有一個觀察:如果我從另一個應用程序調用petDao.storePhoto((長)0,照片)或在PetDao.storePhoto方法使用PMF的一個單獨的實例,然後DataNucleus將將不發射SELECT到檢索圖像對象。

回答

0

得到答案DataNucleus Performance Tuning,其中建議設置DataNucleus將。persistenceByReachabilityAtCommit = false如果應用程序不需要覆蓋能力。將其設置爲false,可以解決圖像檢索問題,而不會對寵物/照片產生任何其他副作用。

從DN文檔,如果新持久對象是存儲在提交可達 ,如果他們不是,他們是從數據庫中刪除

DataNucleus將驗證報價。這個 進程鏡像垃圾收集,其中未引用 的對象被垃圾收集或從內存中移除。可達性是 昂貴,因爲它遍歷整個對象樹,並可能需要從數據庫中重新加載數據 。如果您的 應用程序不需要可達性,則應該禁用它。

在將其設置爲false之前,檢查您的應用是否需要伸縮能力。

1

如果1-N關係可能變大,您可能需要考慮將其關聯映射,即不要映射Pet.photos,映射Photo.pet。這會阻止你在沒有查詢的情況下以OO方式從寵物導航到照片,但會阻止你關心的SQL語句。

您storePhoto會看起來像下面那樣,1-N不會被提取。

public void storePhoto(Photo photo) { 
    // get PM and current tx 
    try { 
     tx.begin(); 
     pm.makePersistent(photo); // assuming pet was already set 
     tx.commit(); 
    } catch (Exception e) { 
     // rollback and close pm 
    } 
} 
+0

爲了便於理解,我給了PET/Photo示例。這個問題更多的是關於JDO優化和延遲加載,而不是對象建模。 1到N構造是一種經常使用的關係,JDO/DataNucleus通過在應用程序實際訪問對象時延遲加載對象來很好地處理它。正如我在上次觀察中提到的那樣,DataNucleus在從不同PMF發射照片對象時不會加載照片對象。所以,我更感興趣的是知道爲什麼DataNucleus在應用程序代碼沒有訪問它們(即照片對象)時正在獲取Photo對象。 – Maithilish

+0

Pet.addPhoto()不可避免地會訪問pet.photos列表來添加一個,這將觸發列表中所有元素的獲取。我不知道有什麼方法與列表映射。 – TheArchitect

+0

是的,我同意,它必須獲取列表中的所有元素。因此,它將加載列表的所有照片,但它只能檢索Photo.id和Photo.desc字段(因爲它們屬於默認提取組),並推遲加載Photo.image字段(JDO的延遲加載功能)直到圖像被應用程序代碼訪問,因爲它不屬於默認獲取組。當您逐一檢索寵物並訪問圖像時,Photo.image字段的延遲加載完全按預期發生。只有當您持續一個新的Pet,然後在同一會話(或PMF)中調用Pet.addPhoto()時,纔會急於加載圖像表面。 – Maithilish

相關問題