Reputation: 241
I have a simple repository backed up by 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);
}
}
This is really simple and is OK. Unfortunately the requirements changed and now I will need to read a lot of and save a lot of widgets - during single business call. Also, the number of business calls will grow.
For instance, this could be the business logic in a separate class:
@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);
}
}
I am affraid this will kill the performance. What can I do to save the performance?
Some ideas / snippets are really welcome, since I am a Hibernate novice.
Upvotes: 1
Views: 76
Reputation: 125252
Your current solution is creating a lot of transactions. 2 transactions for each item, 1 for the read and 1 for the write.
Creating a transaction is a heavy and time consuming operation (generally) as it will open a connection to the database, start a hibernate session and do some synchronization.
Preferably your whole method is a single transaction and this can be accomplished by annotating your method with @Transactional
.
@Scheduled(fixedDelay = 100L)
@Transactional
public void updateWidgets(List<Long> ids){ ... }
When doing this and you have large amounts of data you might want to flush
and clear
your current session once in a while.
If you don't want this you should at least make your read and write in a single transaction. For this you can use a TransactionTemplate
and use this inside your for loop.
@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);
}
}
}
Or move the code in your for loop to a service method which is annotated with @Transactional
.
Upvotes: 1