victordobry
victordobry

Reputation: 3408

Don't understand behavior of nested transactions in Spring

My database has triggers. They trigger after a creation of an entity. I want to test a condition, which depends on results of the trigger execution. So, I need to be able to see those results inside my test. But triggers will trigger after a commit, when the transaction will actually be rolled back.

It seems, that I need to create a new transaction using transactionTemplate and PROPAGATION_REQUIRES_NEW. I tried this way, and I able to see results of a trigger execution (horray!). But this way creates another problem: look at the code, I tried to explain a strange behavior via comments.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class})
@Transactional
public class ServiceTest {

    @Inject
    private PlatformTransactionManager txManager;

    <...>

    @Before
    public final void setUp() {
        clearDatabase();
    }

    @Test
    public final void testFilter() {
        // Note: here database is empty - was cleared by setUp() method
        TransactionTemplate tt = new TransactionTemplate(txManager);
        tt.setPropagationBehavior(PROPAGATION_REQUIRES_NEW);
        tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus s) {
                createAndSaveEntity();
            }
        });
        // Here I can see created entity and results of the trigger execution
        // But also I see all entities, which was in the database before setUp()
        // That is very strange! Why they appear if I deleted them?
        <...>
    }
}

PS: I use Spring Data Neo4j 4.0.0.RELEASE and Neo4j 2.3.1

Upvotes: 0

Views: 305

Answers (1)

Michal Bachman
Michal Bachman

Reputation: 2661

Neo4j does not support nested transactions. Therefore, if a transaction event handler (which I assume you're (correctly) referring to as "trigger") enriches a transaction, it needs to do so in beforeCommit() and it will participate in the all-or-nothing operation. Your best bet for testing is let the transaction commit, assert what you need to assert, and clear the database before or after every test.

(GraphAware RestTest may help with the assertions and clearing, if you really are running against a remote database. If you're using embedded mode for testing, go for GraphUnit.)

Your problem is actually something different though. It looks like something (like the SDN Session) is not getting cleared between test runs. Either clear it explicitly, or annotate your test with @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD).

Upvotes: 2

Related Questions