SQL Set transaction - sql

What happens if you don't use 'Begin Transaction' with an update query for example? Is it still saved in the transaction log?
Say you run the following, will it still be saved to the transaction log automatically? As you can see No 'begin transaction', commit, etc is used below.
UPDATE Customers
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE CustomerID = 1;
I think I'm a little confused on transaction log vs transaction? I think I though setting 'begin transaction' was mandatory for a transaction to be saved in the transaction log?
Thank you

Although BEGIN TRANSACTION starts a local transaction, it is not
recorded in the transaction log until the application subsequently
performs an action that must be recorded in the log, such as executing
an INSERT, UPDATE, or DELETE statement. An application can perform
actions such as acquiring locks to protect the transaction isolation
level of SELECT statements, but nothing is recorded in the log until
the application performs a modification action.
https://technet.microsoft.com/en-us/library/ms188929(v=sql.105).aspx

Related

SQL Server How to always rollback the entire transaction

I have a somewhat unusual need for my transaction handling.
I am working on a mutation test framework for SQL Server, for this I need to run my tests inside a transaction, so that the database always is in the state it started when the tests finish.
However I have the problem that users can code inside the test procedures and may call rollback transaction that may or may not be inside a (nested) transaction (savepoint).
high level it looks like this
start transaction
initialize test
run test with user code
may or may not contain:
- start tran
- start tran savename
- commit tran
- commit tran savename
- rollback tran
- rollback tran savename
output testresults
rollback transaction
Is there a way to make sure I can at last always roll back to the initial state? I have to take in account that users can call stored procedures/triggers that maybe nested and can all contain transaction statements. With all my solutions the moment a user uses rollback tran in their test code they escape the transaction and not everything will be cleaned
What I want is that if a user calls rollback only their part of the transaction is rolled back and my transaction that I start before the initialization of the test is still intact.
If it is possible I want to prevent to force my users to use a transaction template that uses savepoints when a transaction already exists.
I do not think this is possible without any communication/rules for the user code. Despite what you do, if the user's code runs as many COMMITs as there are ##TRANCOUNT at that time, the transaction will be commited and there will be nothing you can do about that.
One way you could do this is if you check/enforce the user code to, instead of using COMMIT, change that to if ##TRANCOUNT>=2 COMMIT. This will make sure the TRUE data commit can only be done by YOUR COMMIT command. Of course, it happens you never really want to commit, so you just rollback and it's over.
You mention:
What I want is that if a user calls rollback only their part of the
transaction is rolled back
Please note that nested transactions are kind of a myth. Refer to this excellent article. Long story short: "Nested" BEGIN TRANSACTIONs and COMMITs do actually nothing except change the value of the system var ##TRANCOUNT so that some organisation can be made through procedures.
I don't think it is possible to rollback a part of transaction and keep the other transaction intact. The moment we rollback the transaction, the entire transaction gets rolled back.
As pointed out by serveral others nested transactions are not supported in SQL Server. I have decided to minimize the number of state changing statements after the users code and that I clean those statements at the start of a test batch. This way it doesn't really matter that I can't rollback my own transaction, since the heavy lifting will be rolled back either by me or the user.
I also decided to fail the test when the starting ##TRANCOUNT and the ending ##TRANCOUNT dont match up so that no test can pass when there is something wrong with the users transactions.
The current system however will still struggle with a user doing a COMMIT TRAN. That is a problem for another time.
I believe the actual need is to write the test cases for T-SQL. If that is correct then I feel you don't have to reinvent the wheel and start using the open source test framework T-SQLT https://tsqlt.org/

Update inside a read uncommitted transaction

I am having an SP with transaction isolation level set as Read Uncommitted.
For Example
Create Procedure TrailSP
AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRY
UPDATE TrialTable
SET TrailColumn ='Update'
WHERE TrailID=1
--this is followed by more updates and selects
END TRY
BEGIN CATCH
RETURN -1;
END CATCH
RETURN 0;
what I want to know is that the first update I have given in the SP will it get committed instantly as it executes or will it get committed along with the rest of the logic at the end of Sp.
It will get committed, as any update under any transaction isolation level, when the transaction commits. This has nothing to do with the stored procedure ending.
If the call to your procedure has a transaction, then the commit will occur when that transaction commits.
If the call to your procedure does not have a transaction but the session has enabled implicit transactions then it will commit when the application explicitly commits.
If the call to your procedure does not have a transaction and session has the auto commit transaction behavior (ie. the most common case) then transaction will commit when the UPDATE statement completes.
Enabling READ UNCOMMITTED for an UPDATE is a no-op.
-Any data read inside a READ UNCOMMITTED is data that could disappear because the transaction that wrote it rollback.
-Its also possible to not see some row that have been committed because a transaction that have not yet committed and might never commit deleted it.
-Its also possible for row to be missing or be duplicated because of PageSplit.
Basically anything is possible, so the data read should never be used to compute anything that should be written to the database or you risk corrupting your database.
TLDR: never use READ UNCOMMITTED

How to return back in SQL statement

I have run SQL server command (update command).
the command has been performed successfully and the table has been updated
is there any way to take back in that command ?
note: no backup taken
If you had originally asked the question how do I do an UPDATE with the possibility of ROLLBACK I would tell you you should do your ad-hoc updates like this.
BEGIN TRANSACTION
UPDATE blah
SET value = newvalue
WHERE condition = someothervalue
--COMMIT TRANSACTION
Then if the results are as expected run the COMMIT TRANSACTION. If they are not than you could do a ROLLBACK TRANSACTION. However since you already did the updates and have no backups or recovery plan you are pretty much out of luck.
After you have already executed an update command the only way back would be via restoring a backup.
Something I do when writing any modification scripts is to wrap the command in a transaction and then either run a rollback or a commit depending on if the query performed as suspected.
Example:
--start the transaction only execute the first three lines, this leaves the transaction open
BEGIN TRANSACTION
UPDATE TABLEA
SET COL1 = "newValue"
--examine data and based on the results run one of these two lines
ROLLBACK TRANSACTION
COMMIT TRANSACTION

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.

Does a transaction affect all queries?

I started a transaction using BEGIN TRANSACTION in Management Studio but I forgot to ROLLBACK or COMMIT it for about 10 minutes. I freaked out and went back to ROLLBACK my changes. Did this rollback all queries that went through the server during that time or just through my user/connection?
Just your connection :-)
(Edit: rather your transaction, since the BEGIN TRANSACTION. If you did updates before the BEGIN TRANSACTION in the same session, they will of course not be rolled back)
BUT: It could have given SELECTs of other sessions the wrong answer depending on what lock types and query hints that were being used...
An example:
In one SQL Studio session, do the following:
CREATE TABLE a(a INT)
INSERT INTO a VALUES(1)
BEGIN TRANSACTION
UPDATE a
SET a = 2
SELECT *, ##TRANCOUNT
FROM a
-> You will see '2, 1' as result
Open a new session (tab in Sql studio)
Do:
SELECT *, ##TRANCOUNT
FROM a (NOLOCK)
You will see '2, 0'
Now, in first session, do
ROLLBACK TRANSACTION
SELECT *, ##TRANCOUNT
FROM a
-> transaction rolled back, and you see '1, 0'
-> a select in second session will also show '1, 0'
so: If you use (NOLOCK) hint, you can get uncommitted data as result -> which might lead to very unexpected effects :-)
Dont forget:
DROP TABLE a
when you're done ;)
It should only affect your transaction, so only things that were done in your session during that time.
You're fine. All the other queries will go through just fine.
It should roll back all queries made in the transaction, so it is more specific than your user\connection and definitely not all queries on the box.
You need to review the ACID properties of transactions. You see that there is nothing to worry about if a transaction is rolled back or committed it has no effect on the outcome of other transactions.
Your rollback affects only your transaction. The I in ACID.
However, the rows, pages or whole table you locked will affect other users if they want to use them. It depends on:
what they want to do
lock timeout
client command timeout