Management Studio 2005: Will Cancelling a Statement trigger a Rollback? - sql

A few minutes ago, while working out a new sproc, I executed the wrong delete statement. Something like this:
Delete From SomeTable Where SomeStatusID=1
10 seconds into it, I realized that I typed in the wrong status and hit cancel. It said that the statement was canceled.
I did a restore to a separate database to get back the table that I just presumably nuked, thinking that since this was not in a transaction some records were probably deleted.
Oddly, the records were all intact. Just curious as to why this was -- did it treat the individual delete statement as a transaction in this case, even though there was not an explicit transaction defined?

By default, a single DML statement is executed as a transaction. If the statement succeeds, the transaction is committed. If the statement is cancelled or otherwise fails, the transaction is rolled back.
This behavior is built in to the engine, and is not related to management studio. See Autocommit Transactions in the docs.

There are always transactions. The only thing that changes is how those transactions are isolated from each other and that in management studio the transaction might not be defined explicitly and is auto-committed when the query finishes.

Related

What will happen if I execute rollback statement on simple select query

I executed a simple SQL performance query to retrieve the sessions running currently in the database in Oracle sql developer.
But accidentally my cursor clicked on the roll back icon and it got rolled back.
Could you please tell me What happens to the entire database after this?
Rolling back a select does nothing as long as you didn't make changes to the database without committing the transaction.
In oracle clients when you run a query that modifies the database, the query is first run. Another step is then needed to commit the transaction.
MS SQL Server has a similar concept where you can do safe transactions like
begin tran
delete from table where val > 5
rollback{commit}
This allows you to look at the number of records your SQL statement have done prior to committing the transaction. If you want you can choose to rollback or commit your transaction.
What exactly did you roll back? That "simple SQL performance query", or "sessions running currently in the database in Oracle SQL Developer"?
If former, nothing happened, SELECT didn't do any changes anyway. If it were SELECT ... FOR UPDATE, lock would have been released.
If latter, then any changes you did in the database since previous COMMIT were rolled back (as you didn't roll back to a savepoint), so - nothing happened either.
What happens to the entire database after this?
It returned to state it was in earlier, as if you didn't touch anything at all.

Does stopping query with a rollback guarantee a rollback

Say I have a query like this:
BEGIN Transaction
UPDATE Person SET Field=1
Rollback
There are one hundred million people. I stopped the query after twenty minutes. Will SQL Server rollback the records updated?
A single update will not update some rows. It will either update all or 0.
So, if you cancel the query, nothing will be updated.
This is atomicity database systems which SQL Server follows.
In other words, you don't have to do that rollback at the end, nothing was committed anyway.
When you cancel a query, it will still hold locks until everything is rolled back so no need to panic.
You could test it yourself, execute the long query, cancel it and you will notice that it takes a while before the process really end.
While the update statement will not complete, the transaction will still be open, so make sure you rollback manually or close out the window to kill the transaction. You can test this by including two statements in your transaction, where the first one finishes and you cancel while it's running the second - you can still commit the transaction after stopping it, and then get the first half of your results.
BEGIN Transaction
UPDATE Person SET Field=1 WHERE Id = 1
UPDATE Person SET Field=1
Rollback
If you start this, give it enough time for the first line to finish, hit the Stop button in SSMS, then execute commit transaction, you'll see that the first change did get applied. Since you obviously don't want part of a transaction to succeed, I'd just kill the whole window after you've stopped it so you can be sure everything's rolled back.
Since you have opened the Transaction, Stoping the Query manually does not completes the transaction, This transaction will still be open and all the subsequent requests to this table will be blocked.
You can do any one of following options
Kill the Connection using the command KILL SPID (SPID is the process ID of your connection)
Note: This will auto rollback the changes you made, you can monitor the rollback status with command KILL SPID WITH STATUSONLY (After killing)
run the ROLLBACK command manually
** SPID is your request id, you can find it from sys.sysprocesses table/ you can also find it on Management Studio query Window the number which is within brackets / also you can find it at bottom right corner of your management studio beside the login name.
Example SQLQuery2.sql... (161) -- 161 is your spid.

Rollback to savepoint doesn't release locks

I think I have a misunderstanding about how to use Savepoints. Perhaps someone can clear it up for me. I present my example as what I am trying to do, and what I have experienced.
My app is doing a certain procedure.
Before that procedure (and associated DB operations) I create a savepoint.
During that procedure, I initiate a select for update,
which creates a number of locks:
lock1 - duration=transaction, class=row, type=intent row=big number
lock2 - duration=transaction, class=row, type=WriteNoPK row=big number
Should that java procedure succeed, the associated DB transaction is completed via a commit.
However, if the java procedure fails, I want also to rollback any associated DB operations.
I have been attempting this by:
conn.rollback(mySavepoint);
However, this has not been releasing the table locks created (above) by the DB operations (that I thought I just rolled back by conn.rollback(mySavepoint);)
I have tested this behaviour with two databases: Sybase, and Derby.
Why is this the case?
Do I really need to commit after the conn.rollback(mySavepoint) ???
It just seems a bit counter-intuitive.

batch procedure, when to commit transactions?

I'm pretty new to PL-SQL although I've got lots of db experience with other RDBMS's. Here's my current issue.
procedure CreateWorkUnit
is
update workunit
set workunitstatus = 2 --workunit loaded
where
SYSDATE between START_DATE and END_DATE
and workunitstatus = 1 --workunit created;
--commit here?
call loader; --loads records based on status, will have a commit of its own
update workunit wu
set workunititemcount = (select count(*) from workunititems wui where wui.wuid = wu.wuid)
where workunitstatus = 2
So the behaviour I'm seeing, with or without commit statements is that I have to execute twice. Once to flip the statuses, then the loader will run on the second execution. I'd like it all to run in one go.
I'd appreciate any words of oracle wisdom.
Thanks!
When to commit transactions in a batch procedure? It is a good question, although it only seems vaguely related to the problems with the code you post. But let's answer it anyway.
We need to commit when the PL/SQL procedure has completed a unit of work. A unit of work is a business transaction. This would normally be at the end of the program, the last statement before the EXCEPTION section.
Sometimes not even then. The decision to commit or rollback properly lies with the top of the calling stack. If our PL/SQL is being called from a client (may a user clicking a button on a screen) then perhaps the client should issue the commit.
But it is not unreasonable for a batch process to manage its own commit (and rollback in the case of errors). But the main point is that the only the toppermost procedure should issue COMMIT. If a procedure calls other procedures those called programs should not issue commits or rollbacks. If they should handle any errors (log etc) and re-raise them to the calling program. Let it decode whether to rollback. Because all the called procedures run in the same session and hence the same transaction: a rollback in a called program will revert all the changes in the batch process. That's not right. The same reasoning applies to commits.
You will sometimes read advice on using intermittent commits to break up long running processes into smaller units e.g. every 1000 inserts. This is bad advice for several reasons, not all of them related to transactions. The pertinent ones are:
Issuing a commit frees locks on resources. This is the cause of ORA-1555 Snapshot too old errors.
It also affects read consistency, which only applies at the statement and/or transaction level. This is the cause of ORA-1002 Fetch out of sequence errors.
It affects re-startability. If the program fails having processed 30% of the records, can we be confident it will only process the remaining 70% when we re-run the batch?
Once we commit records other sessions can see those changes: does it make sense for other users to see a partially changed view of the data?
So, the words of "Oracle wisdom" are: always align the database transaction with the business transaction, with a single commit per unit of work.
Somebody mentioned autonmous transactions as a way of issuing commits in sub-processes. This is usually a bad idea. Changes made in an autonomous transaction are visible to other sessions but not to our own. That very rarely makes sense. It also creates the same problems with re-startability which I discussed earlier.
The only acceptable use for automomous transactions is recording activity (error log, trace, audit records). We need that data to persist regardless of what happens in the wider transaction. Any other use of the pragma is almost certainly a workaround for a porr design, which actually just makes the problem worse.
You may not need to commit in pl/sql procedure. the procedures that you call inside another procedure will use same session so you don't need to commit. by the way procedure must completely rollback if it session rollbacked or has an exception.
I mis-classfied my problem. I thought this was a transaction problem and really it was one of my flags not being set as expected.A number field was null when I was expecting 0.
Sorry for that.
Josh Robinson

Is there a difference between a SELECT statement inside a transaction and one that is outside of it?

Does the default READ COMMITTED isolation level somehow makes the SELECT statement act different inside of a transaction than one that is not in a transaction?
I am using MS SQL.
Yes, the one inside the transaction can see changes made by other previous Insert/Update/delete statements in that transaction; a Select statement outside the transaction cannot.
If all you are asking about is what the Isolation Level does, then understand that all Select statements (hey, all statements of any kind) - are in a transaction. The only difference between one that is explicitly in a transaction and one that is standing on its own is that the one that is standing alone starts its transaction immediately before it executes it, and commits or roll back immediately after it executes;
whereas the one that is explicitly in a transaction can (because it has a Begin Transaction statement) can have other statements (inserts/updates/deletes, whatever) occurring within that same transaction, either before or after that Select statement.
So whatever the isolation level is set to, both selects (inside or outside an explicit transaction) will nevertheless be in a transaction which is operating at that isolation level.
Addition:
The following is for SQL Server, but all databases MUST work in the same way. In SQL Server the Query Processor is always in one of 3 Transaction Modes, AutoCommit, Implicit, or Explicit.
AutoCommit is the default transaction management mode of the SQL Server Database Engine. .. Every Transact-SQL statement is committed or rolled back when it completes. ... If a statement completes successfully, it is committed; if it encounters any error, it is rolled back. This is the default, and is the answer to #Alex's question in the comments.
In Implicit Transaction mode, "... the SQL Server Database Engine automatically starts a new transaction after the current transaction is committed or rolled back. You do nothing to delineate the start of a transaction; you only commit or roll back each transaction. Implicit transaction mode generates a continuous chain of transactions. ..." Note that the italicized snippet is for each transaction, whether it be a single or multiple statement transaction.
The engine is placed in Explicit Transaction mode when you explicitly initiate a transaction with BEGIN TRANSACTION Statement. Then, every statement is executed within that transaction until you explicitly terminate the transaction (with COMMIT or ROLLBACK) or if a failure occurs that causes the engine to terminate and Rollback.
Yes, there is a bit of a difference. For MySQL, the database doesn't actually start with a snapshot until your first query. Therefore, it's not begin that matters, but the first statement within the transaction. If I do the following:
#Session 1
begin; select * from table;
#Session 2
delete * from table; #implicit autocommit
#Session 1
select * from table;
Then I'll get the same thing in session one both times (the information that was in the table before I deleted it). When I end session one's transaction (commit, begin, or rollback) and check again from that session, the table will show as empty.
The READ COMMITTED isolation level is about the records that have been written. It has nothing to do with whether or not this select statement is in a transaction (except for those things written during that same transaction).
If your database (or in mysql, the underlying storage engine of all tables used in your select statement) is transactional, then there simply no way to execute it "outside of a transaction".
Perhaps you meant "run it in autocommit mode", but that is not the same as "not transactional". In the latter case, it still runs in a transaction, it's just that the transaction ends immediately after your statement is finshed.
So, in both cases, during the run, a single select statement will be isolated at the READ COMMITTED level from the other transactions.
Now what this means for your READ COMMITTED transaction isolation level: perhaps surprisingly, not that much.
READ COMMITTED means that you may encounter non-repeatable reads: when running multiple select statements in the same transaction, it is possible that rows that you selected at a certain point in time are modified and comitted by another transaction. You will be able to see those changes when you re-execute the select statement later on in the same pending transaction. In autocommit mode, those 2 select statements would be executed in their own transaction. If another transaction would have modified and committed the rows you selected the first time, you would be able to see those changes just as well when you executed the statement the second time.