Пример #1
0
            /// <summary>
            /// Prepare the session for the transaction commit. Run
            /// <see cref="ISessionImplementor.BeforeTransactionCompletion(ITransaction)"/> for the session and for
            /// <see cref="ConnectionManager.DependentSessions"/> if any. <see cref="Lock"/> the context
            /// before signaling it is done, or before rollback in case of failure.
            /// </summary>
            /// <param name="preparingEnlistment">The object for notifying the prepare phase outcome.</param>
            public virtual void Prepare(PreparingEnlistment preparingEnlistment)
            {
                _preparing = true;
                using (_session.BeginContext())
                {
                    try
                    {
                        using (_session.ConnectionManager.BeginProcessingFromSystemTransaction(_useConnectionOnSystemTransactionPrepare))
                        {
                            if (_useConnectionOnSystemTransactionPrepare)
                            {
                                // Ensure any newly acquired connection gets enlisted in the transaction. When distributed,
                                // this code runs from another thread and we cannot rely on Transaction.Current.
                                using (var tx = new TransactionScope(EnlistedTransaction))
                                {
                                    // Required when both connection auto-enlistment and session auto-enlistment are disabled.
                                    _session.JoinTransaction();
                                    _session.BeforeTransactionCompletion(null);
                                    foreach (var dependentSession in _session.ConnectionManager.DependentSessions)
                                    {
                                        dependentSession.BeforeTransactionCompletion(null);
                                    }

                                    tx.Complete();
                                }
                            }
                            else
                            {
                                _session.BeforeTransactionCompletion(null);
                                foreach (var dependentSession in _session.ConnectionManager.DependentSessions)
                                {
                                    dependentSession.BeforeTransactionCompletion(null);
                                }
                            }
                        }
                        // Lock the session to ensure second phase gets done before the session is used by code following
                        // the transaction scope disposal.
                        Lock();

                        _logger.Debug("Prepared for system transaction");
                        _preparing = false;
                        preparingEnlistment.Prepared();
                    }
                    catch (Exception exception)
                    {
                        _preparing = false;
                        _logger.Error(exception, "System transaction prepare phase failed");
                        try
                        {
                            CompleteTransaction(false);
                        }
                        finally
                        {
                            preparingEnlistment.ForceRollback(exception);
                        }
                    }
                }
            }
        /// <inheritdoc />
        public virtual Task ExecuteWorkInIsolationAsync(ISessionImplementor session, IIsolatedWork work, bool transacted, CancellationToken cancellationToken)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (work == null)
            {
                throw new ArgumentNullException(nameof(work));
            }
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            return(InternalExecuteWorkInIsolationAsync());

            async Task InternalExecuteWorkInIsolationAsync()
            {
                DbConnection  connection = null;
                DbTransaction trans      = null;

                try
                {
                    // We make an exception for SQLite and use the session's connection,
                    // since SQLite only allows one connection to the database.
                    connection = session.Factory.Dialect is SQLiteDialect
                                        ? session.Connection
                                        : await(session.Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false);

                    if (transacted)
                    {
                        trans = connection.BeginTransaction();
                    }

                    await(work.DoWorkAsync(connection, trans, cancellationToken)).ConfigureAwait(false);

                    if (transacted)
                    {
                        trans.Commit();
                    }
                }
                catch (Exception t)
                {
                    using (session.BeginContext())
                    {
                        try
                        {
                            if (trans != null && connection.State != ConnectionState.Closed)
                            {
                                trans.Rollback();
                            }
                        }
                        catch (Exception ignore)
                        {
                            _isolatorLog.Debug(ignore, "Unable to rollback transaction");
                        }

                        switch (t)
                        {
                        case HibernateException _:
                            throw;

                        case DbException _:
                            throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t,
                                                             "error performing isolated work");

                        default:
                            throw new HibernateException("error performing isolated work", t);
                        }
                    }
                }
                finally
                {
                    try
                    {
                        trans?.Dispose();
                    }
                    catch (Exception ignore)
                    {
                        _isolatorLog.Warn(ignore, "Unable to dispose transaction");
                    }

                    if (connection != null && session.Factory.Dialect is SQLiteDialect == false)
                    {
                        session.Factory.ConnectionProvider.CloseConnection(connection);
                    }
                }
            }
        }
        /// <inheritdoc />
        public virtual Task ExecuteWorkInIsolationAsync(ISessionImplementor session, IIsolatedWork work, bool transacted, CancellationToken cancellationToken)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (work == null)
            {
                throw new ArgumentNullException(nameof(work));
            }
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            return(InternalExecuteWorkInIsolationAsync());

            async Task InternalExecuteWorkInIsolationAsync()
            {
                DbConnection  connection = null;
                DbTransaction trans      = null;

                // bool wasAutoCommit = false;
                try
                {
                    // We make an exception for SQLite and use the session's connection,
                    // since SQLite only allows one connection to the database.
                    if (session.Factory.Dialect is SQLiteDialect)
                    {
                        connection = session.Connection;
                    }
                    else
                    {
                        connection = await(session.Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false);
                    }

                    if (transacted)
                    {
                        trans = connection.BeginTransaction();
                        // TODO NH: a way to read the autocommit state is needed
                        //if (TransactionManager.GetAutoCommit(connection))
                        //{
                        //  wasAutoCommit = true;
                        //  TransactionManager.SetAutoCommit(connection, false);
                        //}
                    }

                    await(work.DoWorkAsync(connection, trans, cancellationToken)).ConfigureAwait(false);

                    if (transacted)
                    {
                        trans.Commit();
                        //TransactionManager.Commit(connection);
                    }
                }
                catch (Exception t)
                {
                    using (session.BeginContext())
                    {
                        try
                        {
                            if (trans != null && connection.State != ConnectionState.Closed)
                            {
                                trans.Rollback();
                            }
                        }
                        catch (Exception ignore)
                        {
                            isolaterLog.Debug(ignore, "Unable to rollback transaction");
                        }

                        if (t is HibernateException)
                        {
                            throw;
                        }
                        else if (t is DbException)
                        {
                            throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t,
                                                             "error performing isolated work");
                        }
                        else
                        {
                            throw new HibernateException("error performing isolated work", t);
                        }
                    }
                }
                finally
                {
                    //if (transacted && wasAutoCommit)
                    //{
                    //  try
                    //  {
                    //    // TODO NH: reset autocommit
                    //    // TransactionManager.SetAutoCommit(connection, true);
                    //  }
                    //  catch (Exception)
                    //  {
                    //    log.Debug("was unable to reset connection back to auto-commit");
                    //  }
                    //}

                    try
                    {
                        trans?.Dispose();
                    }
                    catch (Exception ignore)
                    {
                        isolaterLog.Warn(ignore, "Unable to dispose transaction");
                    }

                    if (session.Factory.Dialect is SQLiteDialect == false)
                    {
                        session.Factory.ConnectionProvider.CloseConnection(connection);
                    }
                }
            }
        }
Пример #4
0
        /// <inheritdoc />
        public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, bool transacted)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }
            if (work == null)
            {
                throw new ArgumentNullException(nameof(work));
            }

            DbConnection  connection = null;
            DbTransaction trans      = null;

            try
            {
                // We make an exception for SQLite and use the session's connection,
                // since SQLite only allows one connection to the database.
                connection = session.Factory.Dialect is SQLiteDialect
                                        ? session.Connection
                                        : session.ConnectionManager.GetNewConnection();

                if (transacted)
                {
                    trans = connection.BeginTransaction();
                }

                work.DoWork(connection, trans);

                if (transacted)
                {
                    trans.Commit();
                }
            }
            catch (Exception t)
            {
                using (session.BeginContext())
                {
                    try
                    {
                        if (trans != null && connection.State != ConnectionState.Closed)
                        {
                            trans.Rollback();
                        }
                    }
                    catch (Exception ignore)
                    {
                        _isolatorLog.Debug(ignore, "Unable to rollback transaction");
                    }

                    switch (t)
                    {
                    case HibernateException _:
                        throw;

                    case DbException _:
                        throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t,
                                                         "error performing isolated work");

                    default:
                        throw new HibernateException("error performing isolated work", t);
                    }
                }
            }
            finally
            {
                try
                {
                    trans?.Dispose();
                }
                catch (Exception ignore)
                {
                    _isolatorLog.Warn(ignore, "Unable to dispose transaction");
                }

                if (connection != null && session.Factory.Dialect is SQLiteDialect == false)
                {
                    session.Factory.ConnectionProvider.CloseConnection(connection);
                }
            }
        }