1

1 対 N の関係を持つ次の永続クラスがあります。

@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 のField Object 画像は、画像オブジェクトを保持するためにシリアル化されたものです。

データストア操作には、次のメソッドを持つ 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 枚の写真が格納されます。

しかし、petDao.storePhoto((long)0, photo)コードの DataNucleus ログを分析すると、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 "org.datanucleus.store.rdbms.ParamLoggingPreparedStatement@190a0d6"
Persist         [DEBUG] Object "in.m.pet.Photo@10deb5f" 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

INSERT INTO PHOTO... ステートメントを使用して「写真 4」を追加した後、DataNucleus は 3 つの SELECT IMAGE FROM PHOTO ステートメントを起動して、以前の 3 つの画像オブジェクトを取得します。イメージ オブジェクトの数が増えると、これらの取得は非常に大きくなる可能性があり、その結果、データストアに不要な負荷がかかり、パフォーマンスに影響を与えます。

pm.getObjectById() を使用してペットを選択し、Pet オブジェクトを切り離し、切り離されたオブジェクトに写真を追加してから、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((long)0, photo) を呼び出すか、PetDao.storePhoto メソッドで PMF の別のインスタンスを使用すると、DataNucleusSELECT を起動して画像オブジェクトを取得しません。

4

2 に答える 2

0

DataNucleus Performance Tuningで回答を得ました。アプリで到達可能性が必要ない場合は、datanucleus.persistenceByReachabilityAtCommit=falseを設定することをお勧めします。これを false に設定すると、ペット/写真に関するその他の副作用なしに画像取得の問題が解決されます。

DN doc から引用するには

DataNucleus は、新しく永続化されたオブジェクトがコミット時にメモリに到達できるかどうかを確認します。そうでない場合は、データベースから削除されます。このプロセスはガベージ コレクションを反映しており、参照されていないオブジェクトはガベージ コレクションされるか、メモリから削除されます。到達可能性は、オブジェクト ツリー全体をトラバースし、データベースからのデータの再読み込みが必要になる場合があるため、コストがかかります。アプリケーションが到達可能性を必要としない場合は、無効にする必要があります。

false に設定する前に、アプリで到達可能性が必要かどうかを確認してください。

于 2013-10-07T07:31:53.380 に答える