优化几个Hibernate加载/保存调用的思路



我有一个由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);
    }
}

这真的很简单,是OK的。不幸的是,需求发生了变化,现在我需要在单个业务呼叫期间阅读大量内容并保存大量小部件。同时,商务电话的数量也会增加。

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

@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);
    }   
}
我担心这会破坏演出。我能做些什么来保存性能?
  • 我应该加载/保存为批次,即一次全部?我有名单,所以也许有可能?
  • 我应该以某种方式缓存实例而不是在会话中(这是短的,你可以看到)?

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

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

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

最好你的整个方法是一个单一的事务,这可以通过用@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注释的服务方法中。

最新更新