SQL Server Detect Transactions and Commit? - sql-server-2008

I have a long-running script that may or may not have an uncomitted transaction at the end. I would like to have something at the bottom to just clean up and if there is a transaction hanging out somewhere, just commit it, and if there is one another level up, commit that one, etc.
How can I do that?
Thanks!

Loop until all commuted. Strange situation to be in though...
WHILE XACT_STATE() = 1
COMMIT TRAN

Related

How to handle sql.ErrTxDone

I am for example trying to create a new record in my mysql database. In the case of a sql.ErrTxDone, what does it actually mean, what should i do in-case the transaction was committed ?
You get this error if a transaction is in a state where it cannot be used anymore.
sql.Tx:
After a call to Commit or Rollback, all operations on the transaction fail with ErrTxDone.
And also sql.ErrTxDone:
ErrTxDone is returned by any operation that is performed on a transaction that has already been committed or rolled back.
var ErrTxDone = errors.New("sql: transaction has already been committed or rolled back")
What should you do? Don't use the transaction anymore. If you have further task, do it outside of it or in another transaction.
If you have tasks that should be in the same transaction, don't commit it until you do everything you have to. If the transaction was rolled back (e.g. due to a previous error), you have no choice but to retry (using another transaction) or report failure.
If you're already using transactions, try to put everything in the transaction that needs to happen all-or-nothing. That's the point of transactions. Either everything in it gets applied, or none of them. Using them properly you don't have to think about cleaning up after them. They either succeed and you're happy, or they don't and you either retry or report error, but you don't have to do any cleanup.

MySql: SELECT ... FOR UPDATE break before doing the UPDATE

I'm doing a SELECT ... FOR UPDATE to lock one record, then doing some calculations and then doing the actual UPDATE. I'm working on an InnoDB-database.
But the calculations might end up in a state where I do not want to execute the UPDATE. How do I cancel the lock in this situation?
InnoDB is made for this. You need to manage your transactions.
Before doing your SELECT ... FOR UPDATE, do START TRANSACTION.
Then do your SELECT ... FOR UPDATE.
Then do the rest of your database work.
Then do COMMIT.
If you decide you don't want to complete your update work, do ROLLBACK instead of COMMIT, and every change within your transaction is discarded. The database returns to the state right before START TRANSACTION.
Don't forget the COMMIT or ROLLBACK especially when debugging. If you do forget, your database may appear to lock up, because a future SELECT ... FOR UPDATE operation may wait for your COMMIT. (Don't ask how I know this. :-)

Percona XtraDB Cluster multi-node writing and unexpected deadlocks outside of transaction?

I am having trouble finding an answer to this using google or Stack Overflow, so perhaps people familiar with Percona XtraDB can help answer this. I fully understand how unexpected deadlocks can occur as outlined in this article, and the solution is to make sure you wrap your transactions with retry logic so you can restart them if they fail. We already do that.
https://www.percona.com/blog/2012/08/17/percona-xtradb-cluster-multi-node-writing-and-unexpected-deadlocks/
My questions is about normal updates that occur outside of a transaction in auto commit mode. Normally if you are writing only to a single SQL DB and perform an update, you get a last in wins scenario so whoever executes the statement last, is golden. Any other data is lost so if two updates occur at the same time, one of them will take hold and the others data is essentially lost.
Now what happens in a multi master environment with the same thing? The difference in cluster mode with multi master is that the deadlock can occur at the point where the commit happens as opposed to when the lock is first taken on the table. So in auto commit mode, the data will get written to the DB but then it could fail when it tries to commit that to the other nodes in the cluster if something else modified the exact same record at the same time. Clearly the simply solution is to re-execute the update again and it would seem to me that the database itself should be able to handle this, since it is a single statement in auto commit mode?
So is that what happens in this scenario, or do I need to start wrapping all my update code in retry handling as well and retry it myself when this fails?
Autocommit is still a transaction; a single statement transaction. Your single statement is just wrapped up in BEGIN/COMMIT for you. I believe your logic is inverted. In PXC, the rule is "commit first wins". If you start a manual transaction on node1 (ie: autocommit=0; BEGIN;) and UPDATE id=1 and don't commit then on node2 you autocommit an update to the same row, that will succeed on node2 and succeed on node1. When you commit the manual UPDATE, you will get a deadlock error. This is correct behavior.
It doesn't matter if autocommit or not; whichever commits first wins and the other transaction must re-try. This is the reason why we don't recommend writing to multiple nodes in PXC.
Yes, if you want to write to multiple nodes, you need to adjust your code to "try-catch-retry" handle this error case.

Safely delete rows in sqlserver so you can rollback a commit

I asked this question yesterday Funky Delete Issue
Now I'd like to now how to delete safely.
So how do I use commits and transactions and that syntactical sugar to cover my #$$ because yesterday I dumbly deleted 51,000 rows. I had a backup but I still thought HOLY ^%$# that was too easy.
So how do I safely:
DELETE FROM bBoxHeader
WHERE bBoxHeader.bHeaderId <> '1099'
-- Ooops meant that to be equal. How do I roll back?
How do I wrap that so I don't blow away 51000 rows
Whenever you're doing unverified, ad hoc DML against production data, you should always wrap it in a BEGIN TRANSACTION with a subsequent COMMIT and ROLLBACK. If you run it without checking and then realize you messed it up, you can roll it back. Otherwise you can commit it.
BEGIN TRANSACTION;
DELETE ... WHERE ...
-- COMMIT TRANSACTION;
---^^^^^^ if the number of rows affected is correct, highlight this & execute
-- ROLLBACK TRANSACTION;
---^^^^^^^^ otherwise highlight this and execute
Note that this can ALSO cause you to say HOLY whatever because if you forget to run either the rollback or the commit, then go to lunch or go home for the weekend, you might come back to work looking at your pink slip.

Mysql transaction question

My code:
mysql_query("SET AUTOCOMMIT=0");
mysql_query("START TRANSACTION");
insert_query, update_query1, update_query2
mysql_query("COMMIT");
update_query3
Why does update_query3 query doesn't work if I put it after COMMIT? It works if I put it before the COMMIT. Why is that? It's really strange.
Thank you
First you disable auto-commit. Then you begin transaction, make changes and commit them. Then you execute another query that implicitly starts another transaction. In order for changes to get committed, you have to call "COMMIT" explicitly because auto-commit is turned off.
Because COMMIT (or ROLLBACK for that matter) marks the end of the transaction.
You'd have to use:
mysql_query("COMMIT AND CHAIN");
..to create a new transaction to begin as soon as the current one ends, and the new transaction has the same isolation level as the just-terminated transaction.
But it still means you need to have:
mysql_query("COMMIT");
...after the update_query3 to commit the changes.
update_query3 isn't part of any existing transaction. So it starts a new (implicit) transaction.
You never commit the transaction started by update_query3, so it'll get rolled back when you close the connection.