We have a very difficult to track down bug in one of our software solutions that sometimes leaves an open transaction. We have this application in production at a number of sites (read: 70+), and we've only seen this issue twice so far this year at separate locations.
The issue we're having is a transaction that's being left open from the constant connection to the SQL Server. Using dbcc opentran shows that there is a single transaction left open. In today's case, it was open from 9:30 AM before we realized it at 1:00 PM. Closing the program with the connection will result in the transaction being closed/cancelled, and all the data from the day thus far lost.
Using dbcc opentran it responds with the name of the open transaction was user_transaction. Trying to close it with commit tran user_transaction gives an error of The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION..
I can understand you would almost never want to force the transaction to be committed without the prior connection's knowledge, but is there any way to do so? In this case, we closed the program and we lost a half of day's business worth of data.
Thanks.
If it were possible for a transaction to be committed by another conenction, then it's not a transaction. If this were possible, it would open the door to way more issues than it would solve.
See this link: http://ask.sqlservercentral.com/questions/3865/forcing-a-transaction-to-commit.html
Related
I have disabled autocommit in SSMS.
I have been playing around with it today and after some bizarre (to me, anyway) behaviour narrowed the use case to the following:
connect to db
open a new a query (ctrl n)
issue a simple SELECT statement eg
select TOP (5) * from AdventureWorks2017.Person.Person
close the window
I get the following message in a dialog (dialogue, hmm) box:
There are uncommitted transactions. Do you wish to commit these transactions before closing the window?
Being a long-time Oracle user, I was aware there are differences in locking between Oracle and SS, but selects causing an outstanding transaction that needs to be committed or rolled back? Really? This can't be so, surely. No data has changed. Please could somebody explain? Thanks in advance.
When you're working with the console, it automatically puts your queries into a transaction. Because you haven't closed the transaction it automatically started when you started running queries of any kind, you still have a transaction open.
This MSDN article talks a bit about it.
https://learn.microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql
Reason for System.Transactions.TransactionInDoubtException mentions three reasons for transactions being promoted to MSDTC. The first two are fairly well known, however the third reason is the following:
3.If you have "try/catch{retry if timeout/deadlock}" logic that is running within your code, then this can cause issues when the transaction is within a System.Transactions.TransactionScope, because of the way that SQL Server automatically rolls back transaction when a timeout or deadlock occurs.
I am seeing this behavior in one of my server apps when it is under severe load (SQL 2012). I've tried Googling extensively, but I'm not finding any more info. Does anyone have any references to additional information on this topic?
thanks,
Larry
I guess we're really running one transaction over one connection with a ref count of two. Which I agree is bogus and should be re-coded.
This is not a problem by itself.
However, there times when the inner transaction rolls back and retries
The problem is that a rollback rolls back everything. You can't retry the "inner" work in isolation. (Yes, this would be super useful but SQL Server does not support it.)
This looks to fire up a second connection for the inner transaction. Which would cause MSDTC to be invoked to try to coordinate.
This is moot because at this point the "outer" work has been destroyed.
There is no great solution for this problem. The best strategy is likely to have only one transaction and retry outer and inner work as one unit. Retries always must retry the entire transaction. You can use transaction "ref counting" if you want but you can't use it to rollback.
A particular nasty feature of SQL Server is that it is unpredictable whether any particular error causes the transaction to roll back. Therefore it is the cleanest way to never handle errors with SQL Server and always declare the transaction to be lost. (There is no technical reason SQL Server has to do this. It's just a stupid design choice.)
I'm looking for something similiar to an SQL transaction. I need the usual protections that transactions provide, but I don't want it to slow down anyone else.
Imagine client A connects to the DB and runs these commands:
BEGIN TRAN
SELECT (something)
(Wait a few seconds maybe.)
UPDATE (something)
COMMIT
Inbetween the SELECT and the UPDATE, client B comes along and attempts to do a query, that under normal circumstances, would end up having to wait for A to COMMIT.
What I'd like is for client A to open it's transaction in such a way that should B come along and perform it's query, client A will find it's transaction immediately rolled back and it's subsequent commands failing. Client B would only experience minimal delay.
(Note that the SELECT and UPDATE are simply illustrative commands.)
Update...
I've got a high priority task (client B) that sometimes (once a month-ish) gets an SQL timeout error, and a low priority task (client A) with a transaction which causes that timeout. I'd rather that the low priority task fails and is reattempted in the next cycle.
I ended up fixing this problem by eliminating the transactions entirely and replacing them with an informal set of flags. The queries were refactored to only do something if the right set of flags are raised and I added something that cleared up abandoned records that the rollback would have cleared in the past.
I fixed my transaction issues by eliminating transactions.
Using SNAPSHOT isolation level will prevent B from blocking. B will see data in the state they were before A issued BEGIN TRANSACTION. Unless B modifies data, they will never block each other.
While not a transaction at all, Optimistic Concurrency may be useful -- it is used by default in LINQ2SQL, etc.
The general idea is that the data is read -- modifications can be independently made -- and then the data written back with a "check" (this is loosely comparable to a Compare and Swap). If the check fails it is up the application to decide what to do (restart the process, proceed anyway, fail).
This naturally doesn't work for all scenarios and may not detect a number of interactions, such as new items added between the "read" and "write". Both the actual read and write can be in separate transactions with the appropriate isolation level; the separate transactions may allow additional transactions to be interleaved.
Of course, depending upon the exact problem and interactions... different isolation levels and/or finer grained locking may be sufficient.
Happy coding.
That is back to front.
You can't have later clients aborting earlier transactions: that's chaos.
You can have snapshot isolation so that client B has a consistent view and isn't blocked (mostly) by client A. Also Wikipedia for more general stuff
Perhaps describe your problem more fully so we can offer suggestions for that...
One thing that I've seen used (but I'm afraid that I don't have any code handy for it) is having transaction A spawn another process which then monitors the transaction. If it sees any blocks caused by the transaction then it immediately issues a KILL to the spid.
If I can find the code for this then I'll add it here.
I'm facing some locks at our DB server created by our application. What I don't understand is how a process that is Sleeping is having an Open Transaction (that process 71 is the one creating the Lock).
As far as I know when a process finishes it closes all the opened transactions. Is that rigth?
Thanks in advance mates.
As far as I know when a process
finishes it closes all the opened
transactions. Is that right?
No. If you explicitly open a transaction you must explicitly commit or rollback. Until that time the transaction remains open so it is perfectly possible for a connection to be idle (not currently processing any task) but still have an uncommitted transaction.
Many people expect that an error will automatically roll back a transaction but this is not the case unless you have
set xact_abort on
As far as I know when a process
finishes it closes all the opened
transactions. Is that rigth?
Yes. But it is not guaranteed and you should not rely on it. You must explicitly close the connection.
The in-house application framework we use at my company makes it necessary to put every SQL query into transactions, even though if I know that none of the commands will make changes in the database. At the end of the session, before closing the connection, I commit the transaction to close it properly. I wonder if there were any particular difference if I rolled it back, especially in terms of speed.
Please note that I am using Oracle, but I guess other databases have similar behaviour. Also, I can't do anything about the requirement to begin the transaction, that part of the codebase is out of my hands.
Databases often preserve either a before-image journal (what it was before the transaction) or an after-image journal (what it will be when the transaction completes.) If it keeps a before-image, that has to be restored on a rollback. If it keeps an after-image, that has to replace data in the event of a commit.
Oracle has both a journal and rollback space. The transaction journal accumulates blocks which are later written by DB writers. Since these are asychronous, almost nothing DB writer related has any impact on your transaction (if the queue fills up, then you might have to wait.)
Even for a query-only transaction, I'd be willing to bet that there's some little bit of transactional record-keeping in Oracle's rollback areas. I suspect that a rollback requires some work on Oracle's part before it determines there's nothing to actually roll back. And I think this is synchronous with your transaction. You can't really release any locks until the rollback is completed. [Yes, I know you aren't using any in your transaction, but the locking issue is why I think a rollback has to be fully released then all the locks can be released, then your rollback is finished.]
On the other hand, the commit is more-or-less the expected outcome, and I suspect that discarding the rollback area might be slightly faster. You created no transaction entries, so the db writer will never even wake up to check and discover that there was nothing to do.
I also expect that while commit may be faster, the differences will be minor. So minor, that you might not be able to even measure them in a side-by-side comparison.
I agree with the previous answers that there's no difference between COMMIT and ROLLBACK in this case. There might be a negligible difference in the CPU time needed to determine that there's nothing to COMMIT versus the CPU time needed to determine that there's nothing to ROLLBACK. But, if it's a negligible difference, we can safely forget about about it.
However, it's worth pointing out that there's a difference between a session that does a bunch of queries in the context of a single transaction and a session that does the same queries in the context of a series of transactions.
If a client starts a transaction, performs a query, performs a COMMITor ROLLBACK, then starts a second transaction and performs a second query, there's no guarantee that the second query will observe the same database state as the first query. Sometimes, maintaining a single consistent view of the data is of the essence. Sometimes, getting a more current view of the data is of the essence. It depends on what you are doing.
I know, I know, the OP didn't ask this question. But some readers may be asking it in the back of their minds.
In general a COMMIT is much faster than a ROLLBACK, but in the case where you have done nothing they are effectively the same.
The documentation states that:
Oracle recommends that you explicitly end every transaction in your application programs with a COMMIT or ROLLBACK statement, including the last transaction, before disconnecting from Oracle Database. If you do not explicitly commit the transaction and the program terminates abnormally, then the last uncommitted transaction is automatically rolled back. A normal exit from most Oracle utilities and tools causes the current transaction to be committed. A normal exit from an Oracle precompiler program does not commit the transaction and relies on Oracle Database to roll back the current transaction.
http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_4010.htm#SQLRF01110
If you want o choose to do one or the other then you might as well do the one that is the same as doing nothing, and just commit it.
Well, we must take into account what an SELECT returns in Oracle. There are two modes. By default an SELECT returns data as that data looked in the very moment the SELECT statement started executing (this is default behavior in READ COMMITTED isolation mode, the default transactional mode). So if an UPDATE/INSERT was executed after SELECT was issued that won't be visible in result set.
This can be a problem if you need to compare two result sets (for example debta and credit sides of an general ledger app). For that we have a second mode. In that mode SELECT returns data as it looked at the moment the current transaction began (default behavior in READ ONLY and SERIALIZABLE isolation levels).
So, at least sometimes it is necessary to execute SELECTs in transaction.
Since you've not done any DML, I suspect there'd be no difference between a COMMIT and ROLLBACK in Oracle. Either way there's nothing to do.
I'd think a Commit would be more efficient; since generally you'd expect most DB transactions to be committed; so you would think the DB optimizes for this case (as opposed to trying to be more efficient for a rollback).