0

アプリケーションが必要とするメモリを最小限に抑えるために、サービス クラスでどの注釈を使用すればよいかわかりません。

1 人の顧客による最大の合計支出を見つけたい顧客/注文のシナリオを考えてみましょう。合計で 100 万件の注文と 100 人の顧客があり、各顧客は 10,000 件の注文を行っています。

私が考えることができる最も簡単な例は次のとおりです。

public class MyService {
    @Transactional(readOnly=true)
    public int getMaxSpend() {
        int maxSpend = 0;
        List<Customer> customers = customerDao.findAll();
        for(Customer customer : customers) {
            List<Order> orders = orderDao.getOrders(customer);
            for(Order order : orders) {
                if(order.getTotal() > maxSpend) maxSpend = order.getTotal();
            }
        }
        return maxSpend;
    }
}

トランザクションは各顧客の注文の読み込みにまたがるので、最終的には休止状態のセッションに 100 万個のオブジェクトが存在することになると思いますが、これは理想とはほど遠いものです。Orderその顧客の反復が完了したら、顧客の注文ごとにガベージ コレクションを行うことで、メモリ内のインスタンスの数を最小限に抑えたいと考えています。

次の例では、顧客は注文のコレクションを参照しておらず、注文も顧客を参照していません。

public class MyService {
    @Transactional(propagation=Propagation.NEVER)
    public int getMaxSpend() {
        int maxSpend = 0;
        List<Customer> customers = getAllCustomers();
        for(Customer customer : customers) {
            int customerSpend = getCustomerSpend(customer);
            if(customerSpend > maxSpend) maxSpend = customerSpend;
        }
        return maxSpend;
    }

    @Transactional(readOnly=true)
    private List<Customer> getAllCustomers() {
        return customerDao.findAll();
    }

    @Transactional(readOnly=true)
    private int getCustomerSpend(Customer customer) {
        int customerSpend = 0;
        List<Order> orders = orderDao.getOrders(customer);
        for(Order order : orders) {
            customerSpend += order.getTotal();
        }
        return customerSpend;
    }
}

残念ながら、jprofiler でメモリをプロファイリングすると、まだ 100 万個のインスタンスがOrderロードされています。プライベートメソッドはトランザクションに対応できないと思っていたので、休止状態の例外が発生することを期待していましたが、これは決して起こりませんでした。上記は正しいアプローチで、どういうわけかすでにトランザクションを開いていますか、それとも私の目標を達成する別の方法がありますか?

4

2 に答える 2

1

getTotal()永続フィールドの値を返す場合、最適な方法は集計関数を使用して HQL クエリを記述することです。

select max(o.total) from Order o

clear()または、ループ内で呼び出しdetach()て (または処理済みオブジェクトを呼び出して) 、セッション キャッシュを定期的にクリアすることもできます。キャッシュをクリアすると、エンティティは切り離された状態になり、すぐに GC によって収集されます。これは、Hibernate でバッチ操作を実装するための一般的な方法です。

于 2012-04-16T15:34:33.593 に答える
0

目的の結果を返す単一のSQLステートメントを記述するだけです。

于 2012-04-16T15:31:59.740 に答える