2

I have implemented the persistence layer using Speedment and I would like to test the code using spring boot unit tests. I have annotated my unit tests with the following annotations:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MovieServiceTest {
  ...
}

By default, Spring will start a new transaction surrounding each test method and @Before/@After callbacks, performing a roll back of the transaction at the end. With Speedment however this does not seem to work.

Does Speedment support transactions across several invocations, and if yes, how do I have to configure Spring to use the Speedment transactions or how doe I have to configure Speedment to use the data source provided by Spring?

Dominik
  • 1,058
  • 8
  • 20

3 Answers3

1

Transaction support was added in Speedment 3.0.17. However, it does not integrate with the Spring @Transactional-annotation yet so you will have to wrap the code you want to execute as a single transaction like shown here:

txHandler.createAndAccept(tx ->

    Account sender = accounts.stream()
        .filter(Account.ID.equal(1))
        .findAny()
        .get();

    Account receiver = accounts.stream()
        .filter(Account.ID.equal(2))
        .findAny()
        .get();

    accounts.update(sender.setBalance(sender.getBalance() - 100));
    accounts.update(receiver.setBalance(receiver.getBalance() + 100));

    tx.commit();
}
Emil Forslund
  • 549
  • 4
  • 12
  • I just added transactions to my code as described, but I run into a `java.sql.SQLException`:`Streaming result set com.mysql.jdbc.RowDataDynamic@8c83ced is still active. No statements may be issued when any streaming result sets are open and in use on a given connection. Ensure that you have called .close() on any active streaming result sets before attempting more queries.` How can this problem be fixed? – Dominik Nov 20 '17 at 21:38
  • Sounds like a bug. You should report it to https://github.com/speedment/speedment/issues and add the full stacktrace. – Emil Forslund Nov 21 '17 at 13:05
1

It is likely that you are streaming over a table and then conducts an update/remove operation while the stream is still open. Most database cannot handle having an open ResultSet on a Connection and then perform update operations on the same connection.

Luckily, there is an easy work around: consider collecting the entities you would like to modify in an intermediate Collection (such as a List or Set) and then use that Collection to perform the desired operations.

This case is described in the Speedment User's Guide here

txHandler.createAndAccept(
    tx -> {
       // Collect to a list before performing actions
        List<Language> toDelete = languages.stream()
            .filter(Language.LANGUAGE_ID.notEqual((short) 1))
            .collect(toList());

        // Do the actual actions
        toDelete.forEach(languages.remover());

        tx.commit();
    }
);
0

AFAIK it does not (yet) - correction: it seems to setup one transaction per stream / statement.

See this article: https://dzone.com/articles/best-java-orm-frameworks-for-postgresql

But it should be possible to implement with writing a custom extension: https://github.com/speedment/speedment/wiki/Tutorial:-Writing-your-own-extensions

Edit:

According to a speedment developer one stream maps to one transaction: https://www.slideshare.net/Hazelcast/webinar-20150305-speedment-2

Manuel Manhart
  • 4,819
  • 3
  • 24
  • 28