0

I want to better the performance of a code here, I have this working:

List<Doctor> team = doctorService.getAll(); team.stream() .filter(doctor -> !doctor.equals(msg.getSender())) .forEach(doctor -> { ChatMessageTeam chatMsg = new ChatMessageTeam(); chatMsg.setDoctor(doctor); chatMsg.setMessage(msg); rep.save(chatMsg); });

The rep is a JPA self-build repository.

And I want to parallel this stream, but when I put .parallel on the stream, I got an error, as I saw because entity manager is not prepared to this. So I think (and not found out how) that I can do is accumulate the transactions and flush all them together in a single query then. Other suggestions are welcome too.

Thanks for your time reading this!

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Luiz Rossi
  • 772
  • 5
  • 19
  • Is `rep` a self-built repository? Are you using any framework/library assisting you with your persistence? Depending on that you can declare a single transaction in which you'll then perform your saves. – oschlueter Dec 22 '16 at 13:19
  • Yes, is a self-build repository, I will add this in the question. And the library I use is the JPA. – Luiz Rossi Dec 22 '16 at 13:23

2 Answers2

0

In order to demonstrate an approach to perform multiple database instructions in a single transaction I wrapped your code into a method and then added the @Transactional annotation to this method. That way your method will either be processed in an existing transaction or a transaction will be created for you. If this doesn't work in your environment please provide error messages or stack traces.

import javax.transaction.Transactional;

// ...

@Transactional
public void store() {
    List<Doctor> team = doctorService.getAll();
    team.stream()
            .filter(doctor -> !doctor.equals(msg.getSender()))
            .forEach(doctor -> {
                ChatMessageTeam chatMsg = new ChatMessageTeam();
                chatMsg.setDoctor(doctor);
                chatMsg.setMessage(msg);
                rep.save(chatMsg);
            });
}
oschlueter
  • 2,596
  • 1
  • 23
  • 46
0

I think at your use-case is .parallel slower. But you can wrapp all into one method into your repo for one commit.

    List<Doctor> team = doctorService.getAll();
    List<ChatMessageTeam> cmtList  = team.stream()
        .filter(doctor -> !doctor.equals(msg.getSender()))
        .map(doctor -> new ChatMessageTeam(doctor ,msg))
        .collector(Collectors.toList()));
    rep.saveList(cmtList);


@Transactional
public saveList(List<ChatMessageTeam> list){
    for(ChatMessageTeam ctm: list){
        save(ctm);
    }
}
jklee
  • 2,198
  • 2
  • 15
  • 25
  • Why do you say it will became slower? and your solution will not run the list twice? one at the `for` command, and another on the `stream`? – Luiz Rossi Dec 22 '16 at 14:22
  • The overhead from fork-join is higher than the duration from your executions. http://stackoverflow.com/questions/20375176/should-i-always-use-a-parallel-stream-when-possible saveList is a method from your repo. I would devide the build and save. – jklee Dec 22 '16 at 16:42