code: public <U> CompletableFuture<U> transaction(Function<ReactiveCompletableFutureGenericQueryExecutor, CompletableFuture<U>> transaction){
          return beginTransaction()
                  .thenCompose(queryExecutor -> transaction.apply(queryExecutor) //perform user tasks
                          .thenCompose(res -> queryExecutor.commit() //commit the transaction
                                  .thenApply(v -> res))); //and return the result
      }
docs: Convenience method to perform multiple calls on a transactional QueryExecutor, committing the transaction and
  returning a result.
  @param transaction your code using a transactional QueryExecutor.
  <pre>
  {@code
  ReactiveCompletableFutureGenericQueryExecutor nonTransactionalQueryExecutor...;
  CompletableFuture<QueryResult> resultOfTransaction = nonTransactionalQueryExecutor.transaction(transactionalQueryExecutor ->
  {
  //make all calls on the provided QueryExecutor that runs all code in a transaction
  return transactionalQueryExecutor.execute(dslContext -> dslContext.insertInto(Tables.XYZ)...)
  .thenCompose(i -> transactionalQueryExecutor.query(dslContext -> dslContext.selectFrom(Tables.XYZ).where(Tables.XYZ.SOME_VALUE.eq("FOO")));
  }
  );
  }
  </pre>
  @param <U> the return type.
  @return the result of the transaction.