我有一个由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){ ... }
当你这样做的时候,你有大量的数据,你可能想要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
注释的服务方法中。