Search in sources :

Example 1 with ReactiveTransactionStatus

use of io.micronaut.transaction.reactive.ReactiveTransactionStatus in project micronaut-data by micronaut-projects.

the class DefaultR2dbcRepositoryOperations method withTransaction.

@Override
@NonNull
public <T> Flux<T> withTransaction(@NonNull TransactionDefinition definition, @NonNull ReactiveTransactionOperations.TransactionalCallback<Connection, T> handler) {
    Objects.requireNonNull(definition, "Transaction definition cannot be null");
    Objects.requireNonNull(handler, "Callback handler cannot be null");
    return Flux.deferContextual(contextView -> {
        Object o = contextView.getOrDefault(ReactiveTransactionStatus.STATUS, null);
        TransactionDefinition.Propagation propagationBehavior = definition.getPropagationBehavior();
        if (o instanceof ReactiveTransactionStatus) {
            // existing transaction, use it
            if (propagationBehavior == TransactionDefinition.Propagation.NOT_SUPPORTED || propagationBehavior == TransactionDefinition.Propagation.NEVER) {
                return Flux.error(new TransactionUsageException("Found an existing transaction but propagation behaviour doesn't support it: " + propagationBehavior));
            }
            try {
                return handler.doInTransaction(((ReactiveTransactionStatus<Connection>) o));
            } catch (Exception e) {
                return Flux.error(new TransactionSystemException("Error invoking doInTransaction handler: " + e.getMessage(), e));
            }
        } else {
            if (propagationBehavior == TransactionDefinition.Propagation.MANDATORY) {
                return Flux.error(new NoTransactionException("Expected an existing transaction, but none was found in the Reactive context."));
            }
            return withConnection(connection -> {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Transaction Begin for DataSource: {}", dataSourceName);
                }
                DefaultReactiveTransactionStatus status = new DefaultReactiveTransactionStatus(connection, true);
                Mono<Boolean> resourceSupplier;
                if (definition.getIsolationLevel() != TransactionDefinition.DEFAULT.getIsolationLevel()) {
                    IsolationLevel isolationLevel = getIsolationLevel(definition);
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Setting Isolation Level ({}) for Transaction on DataSource: {}", isolationLevel, dataSourceName);
                    }
                    if (isolationLevel != null) {
                        resourceSupplier = Flux.from(connection.setTransactionIsolationLevel(isolationLevel)).thenMany(connection.beginTransaction()).hasElements();
                    } else {
                        resourceSupplier = Flux.from(connection.beginTransaction()).hasElements();
                    }
                } else {
                    resourceSupplier = Flux.from(connection.beginTransaction()).hasElements();
                }
                return Flux.usingWhen(resourceSupplier, (b) -> {
                    try {
                        return Flux.from(handler.doInTransaction(status)).contextWrite(context -> context.put(ReactiveTransactionStatus.STATUS, status).put(ReactiveTransactionStatus.ATTRIBUTE, definition));
                    } catch (Exception e) {
                        return Mono.error(new TransactionSystemException("Error invoking doInTransaction handler: " + e.getMessage(), e));
                    }
                }, (b) -> doCommit(status), (b, throwable) -> {
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("Rolling back transaction on error: " + throwable.getMessage(), throwable);
                    }
                    return Flux.from(connection.rollbackTransaction()).hasElements().onErrorResume((rollbackError) -> {
                        if (rollbackError != throwable && LOG.isWarnEnabled()) {
                            LOG.warn("Error occurred during transaction rollback: " + rollbackError.getMessage(), rollbackError);
                        }
                        return Mono.error(throwable);
                    }).doFinally((sig) -> status.completed = true);
                }, (b) -> doCommit(status));
            });
        }
    });
}
Also used : TransactionDefinition(io.micronaut.transaction.TransactionDefinition) DataType(io.micronaut.data.model.DataType) ListIterator(java.util.ListIterator) LoggerFactory(org.slf4j.LoggerFactory) Tuples(reactor.util.function.Tuples) R2dbcConversionContext(io.micronaut.data.r2dbc.convert.R2dbcConversionContext) Internal(io.micronaut.core.annotation.Internal) AsyncFromReactiveAsyncRepositoryOperation(io.micronaut.data.runtime.operations.AsyncFromReactiveAsyncRepositoryOperation) ReactiveCascadeOperations(io.micronaut.data.runtime.operations.internal.ReactiveCascadeOperations) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) EachBean(io.micronaut.context.annotation.EachBean) SqlQueryBuilder(io.micronaut.data.model.query.builder.sql.SqlQueryBuilder) Duration(java.time.Duration) DataAccessException(io.micronaut.data.exceptions.DataAccessException) DeleteOperation(io.micronaut.data.model.runtime.DeleteOperation) RuntimeAssociation(io.micronaut.data.model.runtime.RuntimeAssociation) ColumnNameR2dbcResultReader(io.micronaut.data.r2dbc.mapper.ColumnNameR2dbcResultReader) DTOMapper(io.micronaut.data.runtime.mapper.DTOMapper) TransactionDefinition(io.micronaut.transaction.TransactionDefinition) TransactionalAdvice(io.micronaut.transaction.annotation.TransactionalAdvice) DefaultTransactionAttribute(io.micronaut.transaction.interceptor.DefaultTransactionAttribute) RuntimePersistentProperty(io.micronaut.data.model.runtime.RuntimePersistentProperty) Predicate(java.util.function.Predicate) DBOperation(io.micronaut.data.runtime.operations.internal.DBOperation) Set(java.util.Set) AbstractSqlRepositoryOperations(io.micronaut.data.runtime.operations.internal.AbstractSqlRepositoryOperations) Collectors(java.util.stream.Collectors) StoredSqlOperation(io.micronaut.data.runtime.operations.internal.StoredSqlOperation) Executors(java.util.concurrent.Executors) EntityOperation(io.micronaut.data.model.runtime.EntityOperation) PreparedQuery(io.micronaut.data.model.runtime.PreparedQuery) Serializable(java.io.Serializable) Connection(io.r2dbc.spi.Connection) Objects(java.util.Objects) List(java.util.List) ColumnIndexR2dbcResultReader(io.micronaut.data.r2dbc.mapper.ColumnIndexR2dbcResultReader) Stream(java.util.stream.Stream) ReactiveTransactionStatus(io.micronaut.transaction.reactive.ReactiveTransactionStatus) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Dialect(io.micronaut.data.model.query.builder.sql.Dialect) AsyncRepositoryOperations(io.micronaut.data.operations.async.AsyncRepositoryOperations) R2dbcQueryStatement(io.micronaut.data.r2dbc.mapper.R2dbcQueryStatement) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) Named(jakarta.inject.Named) ConnectionFactory(io.r2dbc.spi.ConnectionFactory) NonUniqueResultException(io.micronaut.data.exceptions.NonUniqueResultException) Row(io.r2dbc.spi.Row) Parameter(io.micronaut.context.annotation.Parameter) AnnotationMetadataProvider(io.micronaut.core.annotation.AnnotationMetadataProvider) SqlDTOMapper(io.micronaut.data.runtime.mapper.sql.SqlDTOMapper) BeanProperty(io.micronaut.core.beans.BeanProperty) ArgumentConversionContext(io.micronaut.core.convert.ArgumentConversionContext) AbstractReactiveEntitiesOperations(io.micronaut.data.runtime.operations.internal.AbstractReactiveEntitiesOperations) Tuple2(reactor.util.function.Tuple2) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RuntimeEntityRegistry(io.micronaut.data.model.runtime.RuntimeEntityRegistry) Function(java.util.function.Function) AttributeHolder(io.micronaut.core.attr.AttributeHolder) TypeMapper(io.micronaut.data.runtime.mapper.TypeMapper) ApplicationContext(io.micronaut.context.ApplicationContext) OperationContext(io.micronaut.data.runtime.operations.internal.OperationContext) Nullable(io.micronaut.core.annotation.Nullable) Page(io.micronaut.data.model.Page) R2dbcRepository(io.micronaut.data.r2dbc.annotation.R2dbcRepository) OpContext(io.micronaut.data.runtime.operations.internal.OpContext) Argument(io.micronaut.core.type.Argument) AbstractConversionContext(io.micronaut.data.runtime.support.AbstractConversionContext) AttributeConverterRegistry(io.micronaut.data.model.runtime.AttributeConverterRegistry) DateTimeProvider(io.micronaut.data.runtime.date.DateTimeProvider) ExecutorService(java.util.concurrent.ExecutorService) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec) PagedQuery(io.micronaut.data.model.runtime.PagedQuery) Logger(org.slf4j.Logger) StoredQuerySqlOperation(io.micronaut.data.runtime.operations.internal.StoredQuerySqlOperation) Iterator(java.util.Iterator) Publisher(org.reactivestreams.Publisher) DataConversionService(io.micronaut.data.runtime.convert.DataConversionService) Mono(reactor.core.publisher.Mono) ReactiveTransactionOperations(io.micronaut.transaction.reactive.ReactiveTransactionOperations) InsertBatchOperation(io.micronaut.data.model.runtime.InsertBatchOperation) NonNull(io.micronaut.core.annotation.NonNull) JoinPath(io.micronaut.data.model.query.JoinPath) IsolationLevel(io.r2dbc.spi.IsolationLevel) Flux(reactor.core.publisher.Flux) ConversionContext(io.micronaut.core.convert.ConversionContext) DeleteBatchOperation(io.micronaut.data.model.runtime.DeleteBatchOperation) InsertOperation(io.micronaut.data.model.runtime.InsertOperation) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) RuntimePersistentEntity(io.micronaut.data.model.runtime.RuntimePersistentEntity) AbstractReactiveEntityOperations(io.micronaut.data.runtime.operations.internal.AbstractReactiveEntityOperations) UpdateBatchOperation(io.micronaut.data.model.runtime.UpdateBatchOperation) UpdateOperation(io.micronaut.data.model.runtime.UpdateOperation) RuntimePersistentPropertyConversionContext(io.micronaut.data.runtime.convert.RuntimePersistentPropertyConversionContext) SqlResultEntityTypeMapper(io.micronaut.data.runtime.mapper.sql.SqlResultEntityTypeMapper) Statement(io.r2dbc.spi.Statement) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) IsolationLevel(io.r2dbc.spi.IsolationLevel) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) ReactiveTransactionStatus(io.micronaut.transaction.reactive.ReactiveTransactionStatus) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) DataAccessException(io.micronaut.data.exceptions.DataAccessException) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) NonUniqueResultException(io.micronaut.data.exceptions.NonUniqueResultException) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) NonNull(io.micronaut.core.annotation.NonNull)

Example 2 with ReactiveTransactionStatus

use of io.micronaut.transaction.reactive.ReactiveTransactionStatus in project micronaut-data by micronaut-projects.

the class DefaultReactiveMongoRepositoryOperations method withTransaction.

@Override
@NonNull
public <T> Flux<T> withTransaction(@NonNull TransactionDefinition definition, @NonNull ReactiveTransactionOperations.TransactionalCallback<ClientSession, T> handler) {
    Objects.requireNonNull(definition, "Transaction definition cannot be null");
    Objects.requireNonNull(handler, "Callback handler cannot be null");
    return Flux.deferContextual(contextView -> {
        Object o = contextView.getOrDefault(ReactiveTransactionStatus.STATUS, null);
        TransactionDefinition.Propagation propagationBehavior = definition.getPropagationBehavior();
        if (o instanceof ReactiveTransactionStatus) {
            // existing transaction, use it
            if (propagationBehavior == TransactionDefinition.Propagation.NOT_SUPPORTED || propagationBehavior == TransactionDefinition.Propagation.NEVER) {
                return Flux.error(new TransactionUsageException("Found an existing transaction but propagation behaviour doesn't support it: " + propagationBehavior));
            }
            try {
                return handler.doInTransaction((ReactiveTransactionStatus<ClientSession>) o);
            } catch (Exception e) {
                return Flux.error(new TransactionSystemException("Error invoking doInTransaction handler: " + e.getMessage(), e));
            }
        } else {
            if (propagationBehavior == TransactionDefinition.Propagation.MANDATORY) {
                return Flux.error(new NoTransactionException("Expected an existing transaction, but none was found in the Reactive context."));
            }
            return withClientSessionMany(clientSession -> {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Transaction Begin for MongoDB configuration: {}", serverName);
                }
                DefaultReactiveTransactionStatus status = new DefaultReactiveTransactionStatus(clientSession, true);
                if (definition.getIsolationLevel() != TransactionDefinition.DEFAULT.getIsolationLevel()) {
                    throw new TransactionUsageException("Isolation level not supported");
                } else {
                    clientSession.startTransaction();
                }
                return Flux.usingWhen(Mono.just(status), sts -> {
                    try {
                        return Flux.from(handler.doInTransaction(status)).contextWrite(context -> context.put(ReactiveTransactionStatus.STATUS, status).put(ReactiveTransactionStatus.ATTRIBUTE, definition));
                    } catch (Exception e) {
                        return Flux.error(new TransactionSystemException("Error invoking doInTransaction handler: " + e.getMessage(), e));
                    }
                }, this::doCommit, (sts, throwable) -> {
                    if (LOG.isWarnEnabled()) {
                        LOG.warn("Rolling back transaction on error: " + throwable.getMessage(), throwable);
                    }
                    return Flux.from(sts.getConnection().abortTransaction()).hasElements().onErrorResume((rollbackError) -> {
                        if (rollbackError != throwable && LOG.isWarnEnabled()) {
                            LOG.warn("Error occurred during transaction rollback: " + rollbackError.getMessage(), rollbackError);
                        }
                        return Mono.error(throwable);
                    }).doFinally((sig) -> status.completed = true);
                }, this::doCommit);
            });
        }
    });
}
Also used : TransactionDefinition(io.micronaut.transaction.TransactionDefinition) DataType(io.micronaut.data.model.DataType) BeanContext(io.micronaut.context.BeanContext) LoggerFactory(org.slf4j.LoggerFactory) Tuples(reactor.util.function.Tuples) MongoCollection(com.mongodb.reactivestreams.client.MongoCollection) Internal(io.micronaut.core.annotation.Internal) ReactiveCascadeOperations(io.micronaut.data.runtime.operations.internal.ReactiveCascadeOperations) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) BsonValue(org.bson.BsonValue) EachBean(io.micronaut.context.annotation.EachBean) StoredQuery(io.micronaut.data.model.runtime.StoredQuery) Map(java.util.Map) DataAccessException(io.micronaut.data.exceptions.DataAccessException) DeleteOperation(io.micronaut.data.model.runtime.DeleteOperation) RuntimeAssociation(io.micronaut.data.model.runtime.RuntimeAssociation) CursorType(com.mongodb.CursorType) DeleteOneModel(com.mongodb.client.model.DeleteOneModel) PersistentProperty(io.micronaut.data.model.PersistentProperty) TransactionDefinition(io.micronaut.transaction.TransactionDefinition) RuntimePersistentProperty(io.micronaut.data.model.runtime.RuntimePersistentProperty) Predicate(java.util.function.Predicate) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) BsonDocumentWrapper(org.bson.BsonDocumentWrapper) Collectors(java.util.stream.Collectors) ReactiveMongoDatabaseFactory(io.micronaut.data.mongodb.database.ReactiveMongoDatabaseFactory) PreparedQuery(io.micronaut.data.model.runtime.PreparedQuery) Serializable(java.io.Serializable) Objects(java.util.Objects) List(java.util.List) ReactiveTransactionStatus(io.micronaut.transaction.reactive.ReactiveTransactionStatus) FindPublisher(com.mongodb.reactivestreams.client.FindPublisher) Dialect(io.micronaut.data.model.query.builder.sql.Dialect) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) MongoAggregationOptions(io.micronaut.data.mongodb.operations.options.MongoAggregationOptions) ReplaceOneModel(com.mongodb.client.model.ReplaceOneModel) Parameter(io.micronaut.context.annotation.Parameter) BeanProperty(io.micronaut.core.beans.BeanProperty) AbstractReactiveEntitiesOperations(io.micronaut.data.runtime.operations.internal.AbstractReactiveEntitiesOperations) Tuple2(reactor.util.function.Tuple2) RuntimeEntityRegistry(io.micronaut.data.model.runtime.RuntimeEntityRegistry) CodecRegistry(org.bson.codecs.configuration.CodecRegistry) Function(java.util.function.Function) MongoClient(com.mongodb.reactivestreams.client.MongoClient) ReactorReactiveRepositoryOperations(io.micronaut.data.operations.reactive.ReactorReactiveRepositoryOperations) BsonDocument(org.bson.BsonDocument) ArrayList(java.util.ArrayList) Filters(com.mongodb.client.model.Filters) Bson(org.bson.conversions.Bson) MongoDatabase(com.mongodb.reactivestreams.client.MongoDatabase) OperationContext(io.micronaut.data.runtime.operations.internal.OperationContext) Nullable(io.micronaut.core.annotation.Nullable) Page(io.micronaut.data.model.Page) Argument(io.micronaut.core.type.Argument) RequiresReactiveMongo(io.micronaut.data.mongodb.conf.RequiresReactiveMongo) AttributeConverterRegistry(io.micronaut.data.model.runtime.AttributeConverterRegistry) DateTimeProvider(io.micronaut.data.runtime.date.DateTimeProvider) Collation(com.mongodb.client.model.Collation) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec) PagedQuery(io.micronaut.data.model.runtime.PagedQuery) Logger(org.slf4j.Logger) UpdateOneModel(com.mongodb.client.model.UpdateOneModel) MongoFindOptions(io.micronaut.data.mongodb.operations.options.MongoFindOptions) Publisher(org.reactivestreams.Publisher) DataConversionService(io.micronaut.data.runtime.convert.DataConversionService) Mono(reactor.core.publisher.Mono) ReactiveTransactionOperations(io.micronaut.transaction.reactive.ReactiveTransactionOperations) ClientSession(com.mongodb.reactivestreams.client.ClientSession) InsertBatchOperation(io.micronaut.data.model.runtime.InsertBatchOperation) TimeUnit(java.util.concurrent.TimeUnit) NonNull(io.micronaut.core.annotation.NonNull) Flux(reactor.core.publisher.Flux) AggregatePublisher(com.mongodb.reactivestreams.client.AggregatePublisher) ConversionContext(io.micronaut.core.convert.ConversionContext) DeleteResult(com.mongodb.client.result.DeleteResult) DeleteBatchOperation(io.micronaut.data.model.runtime.DeleteBatchOperation) InsertOperation(io.micronaut.data.model.runtime.InsertOperation) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) RuntimePersistentEntity(io.micronaut.data.model.runtime.RuntimePersistentEntity) AbstractReactiveEntityOperations(io.micronaut.data.runtime.operations.internal.AbstractReactiveEntityOperations) UpdateBatchOperation(io.micronaut.data.model.runtime.UpdateBatchOperation) UpdateOperation(io.micronaut.data.model.runtime.UpdateOperation) DataSettings(io.micronaut.data.runtime.config.DataSettings) Collections(java.util.Collections) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) ClientSession(com.mongodb.reactivestreams.client.ClientSession) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) ReactiveTransactionStatus(io.micronaut.transaction.reactive.ReactiveTransactionStatus) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) DataAccessException(io.micronaut.data.exceptions.DataAccessException) TransactionUsageException(io.micronaut.transaction.exceptions.TransactionUsageException) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) NonNull(io.micronaut.core.annotation.NonNull)

Aggregations

EachBean (io.micronaut.context.annotation.EachBean)2 Parameter (io.micronaut.context.annotation.Parameter)2 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)2 Internal (io.micronaut.core.annotation.Internal)2 NonNull (io.micronaut.core.annotation.NonNull)2 Nullable (io.micronaut.core.annotation.Nullable)2 BeanProperty (io.micronaut.core.beans.BeanProperty)2 ConversionContext (io.micronaut.core.convert.ConversionContext)2 Argument (io.micronaut.core.type.Argument)2 DataAccessException (io.micronaut.data.exceptions.DataAccessException)2 DataType (io.micronaut.data.model.DataType)2 Page (io.micronaut.data.model.Page)2 Dialect (io.micronaut.data.model.query.builder.sql.Dialect)2 AttributeConverterRegistry (io.micronaut.data.model.runtime.AttributeConverterRegistry)2 DeleteBatchOperation (io.micronaut.data.model.runtime.DeleteBatchOperation)2 DeleteOperation (io.micronaut.data.model.runtime.DeleteOperation)2 InsertBatchOperation (io.micronaut.data.model.runtime.InsertBatchOperation)2 InsertOperation (io.micronaut.data.model.runtime.InsertOperation)2 PagedQuery (io.micronaut.data.model.runtime.PagedQuery)2 PreparedQuery (io.micronaut.data.model.runtime.PreparedQuery)2