我有一个由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);
}
}
我担心这会扼杀表演。我该怎么做才能保存性能?
一些想法/ 片段非常受欢迎,因为我是Hibernate新手。
答案 0 :(得分:1)
您当前的解决方案正在创建大量交易。每个项目有2个事务,1个用于读取,1个用于写入。
创建事务是一项繁重且耗时的操作(通常),因为它将打开与数据库的连接,启动休眠会话并进行一些同步。
最好您的整个方法是单个事务,这可以通过使用@Transactional
注释您的方法来完成。
@Scheduled(fixedDelay = 100L)
@Transactional
public void updateWidgets(List<Long> ids){ ... }
执行此操作并且您有大量数据时,您可能需要暂时flush
和clear
当前会话。
如果你不想这样,你至少应该在一次交易中进行读写。为此,您可以使用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
注释的服务方法。