3.8. Transaction events

A transaction event listener can be registered to receive Neo4j database transaction events. Once it has been registered at a DatabaseManagementService instance, it receives transaction events for the database with which it was registered. Listeners get notified about transactions that have performed any write operation, and that will be committed. If Transaction#commit() has not been called, or the transaction was rolled back with Transaction#rollback(), it will be rolled back and no events are sent to the listener.

Before a transaction is committed, the listeners’s beforeCommit method is called with the entire diff of modifications made in the transaction. At this point the transaction is still running, so changes can still be made. The method may also throw an exception, which will prevent the transaction from being committed. If the transaction is rolled back, a call to the listener’s afterRollback method will follow.

The order in which listeners are executed is undefined — there is no guarantee that changes made by one listener will be seen by other listeners.

If beforeCommit is successfully executed in all registered listeners, the transaction is committed and the afterCommit method is called with the same transaction data. This call also includes the object returned from beforeCommit.

In afterCommit the transaction has been closed, and access to anything outside TransactionData requires a new transaction to be opened. A TransactionEventListener gets notified about transactions that have any changes accessible via TransactionData. Some indexing and schema changes will not trigger these events.

The following example shows how to register a listener for a specific database, and perform basic operations on top of the transaction change set.

Register a transaction event listener and inspect the change set:

    public static void main( String[] args ) throws IOException
    {
        FileUtils.deleteRecursively( HOME_DIRECTORY );
        var managementService = new DatabaseManagementServiceBuilder( HOME_DIRECTORY ).build();
        var database = managementService.database( DEFAULT_DATABASE_NAME );

        var countingListener = new CountingTransactionEventListener();
        managementService.registerTransactionEventListener( DEFAULT_DATABASE_NAME, countingListener );

        var connectionType = RelationshipType.withName( "CONNECTS" );
        try ( var transaction = database.beginTx() )
        {
            var startNode = transaction.createNode();
            var endNode = transaction.createNode();
            startNode.createRelationshipTo( endNode, connectionType );
            transaction.commit();
        }
    }

    private static class CountingTransactionEventListener implements TransactionEventListener<CreatedEntitiesCounter>
    {
        @Override
        public CreatedEntitiesCounter beforeCommit( TransactionData data, Transaction transaction, GraphDatabaseService databaseService ) throws Exception
        {
            return new CreatedEntitiesCounter( size( data.createdNodes() ), size( data.createdRelationships() ) );
        }

        @Override
        public void afterCommit( TransactionData data, CreatedEntitiesCounter entitiesCounter, GraphDatabaseService databaseService )
        {
            System.out.println( "Number of created nodes: " + entitiesCounter.getCreatedNodes() );
            System.out.println( "Number of created relationships: " + entitiesCounter.getCreatedRelationships() );
        }

        @Override
        public void afterRollback( TransactionData data, CreatedEntitiesCounter state, GraphDatabaseService databaseService )
        {
            //empty
        }
    }

    private static class CreatedEntitiesCounter
    {
        private final long createdNodes;
        private final long createdRelationships;

        public CreatedEntitiesCounter( long createdNodes, long createdRelationships )
        {
            this.createdNodes = createdNodes;
            this.createdRelationships = createdRelationships;
        }

        public long getCreatedNodes()
        {
            return createdNodes;
        }

        public long getCreatedRelationships()
        {
            return createdRelationships;
        }
    }