Should I commit or rollback a read transaction?

后端 未结 12 1063
臣服心动
臣服心动 2020-12-02 10:42

I have a read query that I execute within a transaction so that I can specify the isolation level. Once the query is complete, what should I do?

  • Commit the tr
相关标签:
12条回答
  • 2020-12-02 11:19

    Consider nested transactions.

    Most RDBMSes do not support nested transactions, or try to emulate them in a very limited way.

    For example, in MS SQL Server, a rollback in an inner transaction (which is not a real transaction, MS SQL Server just counts transaction levels!) will rollback the everything which has happened in the outmost transaction (which is the real transaction).

    Some database wrappers might consider a rollback in an inner transaction as an sign that an error has occured and rollback everything in the outmost transaction, regardless whether the outmost transaction commited or rolled back.

    So a COMMIT is the safe way, when you cannot rule out that your component is used by some software module.

    Please note that this is a general answer to the question. The code example cleverly works around the issue with an outer transaction by opening a new database connection.

    Regarding performance: depending on the isolation level, SELECTs may require a varying degree of LOCKs and temporary data (snapshots). This is cleaned up when the transaction is closed. It does not matter whether this is done via COMMIT or ROLLBACK. There might be a insignificant difference in CPU time spent - a COMMIT is probably faster to parse than a ROLLBACK (two characters less) and other minor differences. Obviously, this is only true for read-only operations!

    Totally not asked for: another programmer who might get to read the code might assume that a ROLLBACK implies an error condition.

    0 讨论(0)
  • 2020-12-02 11:20

    If you begin a transaction, then best practice is always to commit it. If an exception is thrown inside your use(transaction) block the transaction will be automatically rolled-back.

    0 讨论(0)
  • 2020-12-02 11:20

    In your code sample, where you have

    1. // Do something useful

      Are you executing a SQL Statement that changes data ?

    If not, there's no such thing as a "Read" Transaction... Only changes from an Insert, Update and Delete Statements (statements that can change data) are in a Transaction... What you are talking about is the locks that SQL Server puts on the data you are reading, because of OTHER transactions that affect that data. The level of these locks is dependant on the SQL Server Isolation Level.

    But you cannot Commit, or ROll Back anything, if your SQL statement has not changed anything.

    If you are changing data, then you can change the isolation level without explicitly starting a transation... Every individual SQL Statement is implicitly in a transaction. explicitly starting a Transaction is only necessary to ensure that 2 or more statements are within the same transaction.

    If all you want to do is set the transaction isolation level, then just set a command's CommandText to "Set Transaction Isolation level Repeatable Read" (or whatever level you want), set the CommandType to CommandType.Text, and execute the command. (you can use Command.ExecuteNonQuery() )

    NOTE: If you are doing MULTIPLE read statements, and want them all to "see" the same state of the database as the first one, then you need to set the isolation Level top Repeatable Read or Serializable...

    0 讨论(0)
  • 2020-12-02 11:21

    If you set AutoCommit false, then YES.

    In an experiment with JDBC(Postgresql driver), I found that if select query breaks(because of timeout), then you can not initiate new select query unless you rollback.

    0 讨论(0)
  • 2020-12-02 11:23

    Just a side note, but you can also write that code like this:

    using (IDbConnection connection = ConnectionFactory.CreateConnection())
    using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
    using (IDbCommand command = connection.CreateCommand())
    {
        command.Transaction = transaction;
        command.CommandText = "SELECT * FROM SomeTable";
        using (IDataReader reader = command.ExecuteReader())
        {
            // Do something useful
        }
        // To commit, or not to commit?
    }
    

    And if you re-structure things just a little bit you might be able to move the using block for the IDataReader up to the top as well.

    0 讨论(0)
  • 2020-12-02 11:36

    If you haven't changed anything, then you can use either a COMMIT or a ROLLBACK. Either one will release any read locks you have acquired and since you haven't made any other changes, they will be equivalent.

    0 讨论(0)
提交回复
热议问题