想要优化一些后续的Hibernate加载/保存调用

时间:2014-07-18 05:13:16

标签: java database spring hibernate persistence

我有一个由Hibernate备份的简单存储库

@Repository
@Transactional(rollbackFor = Exception.class)
public class WidgetDAOImpl implements WidgetDAO {
    @Autowired
    private SessionFactory sf;

    @Override
    public Widget getWidget(long id) {
        return (Widget) sf.getCurrentSession().load(Widget.class, id);
    }

    @Override
    public void saveWidget(Widget w){
        sf.getCurrentSession().saveOrUpdate(w);
    }
}

这很简单,没问题。不幸的是,需求发生了变化,现在我需要阅读大量内容并节省大量小部件 - 在单个商务电话中。此外,商务电话的数量也会增加。

例如,这可能是一个单独的类中的业务逻辑:

@Scheduled(fixedDelay = 100L)                       // lets say this is "often"
public void updateWidgets(List<Long> ids){          // lets say the list is ~10 ids
    for(long id: ids){
        Widget w = widgetDAO.getWidget(id);
        doSomeStuff(w);
        widgetDAO.saveWidget(w);
    }   
}

我担心这会扼杀表演。我该怎么做才能保存性能?

  • 我应该批量加载/保存,即一次性加载?我有ID列表,所以也许可以吗?
  • 我应该以某种方式缓存实例而不是在会话中(这很简短,你可以看到)?

一些想法/ 片段非常受欢迎,因为我是Hibernate新手。

1 个答案:

答案 0 :(得分:1)

您当前的解决方案正在创建大量交易。每个项目有2个事务,1个用于读取,1个用于写入。

创建事务是一项繁重且耗时的操作(通常),因为它将打开与数据库的连接,启动休眠会话并进行一些同步。

最好您的整个方法是单个事务,这可以通过使用@Transactional注释您的方法来完成。

@Scheduled(fixedDelay = 100L)              
@Transactional
public void updateWidgets(List<Long> ids){ ... }        

执行此操作并且您有大量数据时,您可能需要暂时flushclear当前会话。

如果你不想这样,你至少应该在一次交易中进行读写。为此,您可以使用TransactionTemplate并在for循环中使用它。

@Autowired
private TransactionTemplate transactionTemplate;

@Scheduled(fixedDelay = 100L)   
public void updateWidgets(List<Long> ids) {  
    for(long id: ids){
       transactionTemplate.execute(new TransactionCallbackWithoutResult() {
          protected void doInTransactionWithoutResult(TransactionStatus status) {
              Widget w = widgetDAO.getWidget(id);
               doSomeStuff(w);
               widgetDAO.saveWidget(w);
          }
    }   
}

或者将for循环中的代码移动到使用@Transactional注释的服务方法。