0

我不知道在我的服务类上使用什么注释来最小化应用程序所需的内存。

以一个客户/订单场景为例,我想找到单个客户的最大总支出。总共有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;
    }
}

由于交易跨越了每个客户订单的加载,我相信休眠会话中最终会有一百万个对象,这远非理想。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 回答