Are nested transaction supported? - vb6

I have a legacy application coded in vb6 with ADODB library, connecting to a Microsoft SQL server 2008.
Can I create nested transactions (classe Connection.BeginTrans ? )
How can I know if it is supported indeed ?

Microsoft SQL Server 2008 does supported nested transactions.
The best way to tell if it is indeed supported in your code is to check the return value of Connection.BeginTrans. The return value will increment by 1 for each nested transaction.
So, if you call it twice and nested transactions are working, then the return value will be 2. For the third call, it will be 3, etc.
Committing or Rolling Back will decrease the return value by 1.
See here for documentation on the function that says as much:
https://www.w3schools.com/asp/met_conn_begintrans.asp
Good Luck.

Related

Mockito causes false positives in Coverity?

We use Coverity to identify potential security and quality flaws in our Java code. In one of our unit tests, we have some testing that involves database connection code:
Connection connection = mock(Connection.class);
Statement statement = mock(Statement.class);
when(connection.createStatement()).thenReturn(statement);
Coverity complains about a potential resource leak:
CID 21920: Resource leak (RESOURCE_LEAK)4. leaked_resource: Failing to save or close resource created by connection.createStatement()
My understanding of how Mockito works is that connection.getStatement() is never actually called, and so no statement is being created that needs to be closed later. (This is in contrast to the typical case in databases where a JDBC connection would need to be closed.)
Is my understanding correct? Is it fair to say that this is a false report from Coverity, caused by the atypical behavior of getConnection() in the context of mocking? If not, please straighten me out.
I'd say your understanding isn't quite correct.
In your code, connection.createStatement() does get called, but it doesn't get called on a 'real' connection that will create a resource on a database somewhere. The mock Connection implementation that Mockito creates just tracks that the method has been called, and returns null. Later, when the thenReturn() method is called, Mockito can link the call to createStatement() with the value passed to thenReturn() so that the mock Connection can return the mock Statement when the createStatement() method is called on it.
Ultimately, this is a false positive report from Coverity: there is no resource leak issue here. However, there is the question of the value of running a scanner such as Coverity on test code. In particular, I'm not sure how you could have a security flaw in test code, given that it isn't interactive and isn't something that you either ship to customers or upload to a server somewhere.

NHibernate TransactionScope issue with Oracle 11g

The following code snippet works fine with SQL Server 2008 (SP1) but with Oracle 11g the call to session.BeginTransaction() throws an exception with the message ‘Connection is already part of a local or a distributed transaction’ (stack trace shown below). Using the '"NHibernate.Driver.OracleDataClientDriver".
Has anyone else run into this?
using (var scope = new TransactionScope())
{
using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
// do what you need to do with the session
transaction.Commit();
}
scope.Complete();
}
Exception at: at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
at NHibernate.Transaction.AdoTransaction.Begin()
at NHibernate.AdoNet.ConnectionManager.BeginTransaction()
at NHibernate.Impl.SessionImpl.BeginTransaction()
at MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) in S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:line 3103
Inner error message was: Connection is already part of a local or a distributed transaction
Inner exception at: at Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
at Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()
at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
The problem with using only the transaction scope is outlined here:
NHibernate FlushMode Auto Not Flushing Before Find
It appears nhibernate (v3.1 with oracle dialect and 11g db w/opd.net v2.112.1.2) requires it's own transactions to avoid the flushing issue but I haven't been able to get the transaction scope to work with the nhibernate transactions.
I can't seem to get it to work :(
this might be a defect in nhibernate or odp.net, not sure...
found same problem here:
NHibernate 3.0: TransactionScope and Auto-Flushing
FIXED: found a solution! by putting "enlist=dynamic;" into my oracle connection string, the problem was resolved. I have been able to use both the nhibernate transaction (to fix the flush issue) and the transaction scope like so:
ISessionFactory sessionFactory = CreateSessionFactory();
using (TransactionScope ts = new TransactionScope())
{
using (ISession session = sessionFactory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
//do stuff here
tx.Commit();
}
ts.Complete();
}
I checked my log files and found this:
2011-06-27 14:03:59,852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - enlisted into DTC transaction: Serializable
before any SQL was executed on the connection. I will unit test to confirm proper execution. I'm not too sure what serializable is telling me though
Brads answer, using an outer TransactionScope and an inner NHibernate transaction with enlist=dynamic, doesn't seem to work properly. Ok, the data gets committed.
But if you omit the scope.Complete() or raise an exception after tx.Commit() the data still gets committed (for Oracle)! However, for some reason this works for SQL-Server.
NHibernate transactions take care of auto-flush but in the end they call the underlying ADO.NET transaction. While many sources encourage the above pattern as best practice for NHibernate to solve the auto-flush issue, sources discussing native ADO.NET say the contrary: Do NOT use TransactionScope and inner transactions together, not for Oracle and not for SQL-Server. (See this question and my answer)
My conclusion: Do not combine TransactionScope and NHibernate transactions. To use TransactionScope, skip NHibernate transactions and handle the flushing manually (see also NHibernate Flush doc).
One question, why are you doing the inner session.BeginTransaction - since 2.1 GA NHibernate will automatically enroll into TransactionScope contexts so there's no reason to do your own anymore.
From NHibernate cookbook
Remember that NHibernate requires an NHibernate transaction when interacting with the database. TransactionScope is not a substitute. As illustrated in the next image, the TransactionScope should completely surround both the session and NHibernate transaction. The call to TransactionScope.Complete() should occur after the session has been disposed. Any other order will most likely lead to nasty, production crashing bugs like connection leaks.
My opinion is also that it should work with TransactionScope along, but it does not, neither in 3.3.x.x neither in 4.0.0.400 version.
The recipe above may work, but need to test it with nested TrancactionScope, with inner TransactionScope that has a Transaction.Suppress defined (when using SQL), etc...

COMMIT WRITE BATCH NOWAIT in Hibernate

Is it possible to execute COMMIT WRITE BATCH NOWAIT in Hibernate?
I didn't search extensively but I couldn't find any evidence that you can access this functionality at the JDBC driver level.
And this leaves you with the option to specify the COMMIT_WRITE parameter at the instance or session level, if this makes sense for you.
Just in case, let me quote this blog post (I'm pasting the content for reference because the original site is either unavailable or dead and I had to use Google Cache):
Using "Commit Write Batch Nowait" from within JDBC
Anyone who has used the new
asynchronous commit feature of Oracle
10.2 will be aware that it's very useful for transaction processing
systems that would traditionally be
bound by log_file_sync wait events.
COMMIT WRITE BATCH NOWAIT is faster
because it doesn't wait for a message
assuring it that the transaction is
safely in the redo log - instead it
assumes it will make it. This nearly
eliminates log_file_sync events. It
also arguably undermines the whole
purpose of commit, but there are many
situations where the loss of a
particular transaction (say to delete
a completed session) is perfectly
survivable and far more preferable
than being unable to serve incoming
requests because all your connections
are busy with log_file_sync wait
events.
The problem anyone using Oracle's JDBC
driver is that neither the 10.2 or
11.1 drivers have any extensions which allow you to access this functionality
easily - while Oracle have lots of
vendor specific extensions for all
sorts of things support for async
commit is missing.
This means you can:
Turn on async commit at the instance level by messing with the
COMMIT_WRITE init.ora parameter.
There's a really good chance this will
get you fired, as throughout the
entire system COMMIT will be
asynchronous. While we think this is
insane for production systems there
are times where setting it on a
development box makes sense, as if you
are 80% log file sync bound setting
COMMIT_WRITE to COMMIT WRITE BATCH
NOWAIT will allow you to see what
problems you face if you can somehow
fix your current ones.
Change COMMIT_WRITE at the session level. This isn't as dangerous as
doing it system wide but it's hard to
see it being viable for a real world
system with transactions people care
about.
Prepare and use a PL/SQL block that goes "BEGIN COMMIT WRITE BATCH NOWAIT;
END". This is safer than the first
two ideas but still involves a network
round trip.
Wrap your statement in an anonymous block with an asynchronous commit.
This is the best approach we've seen.
Your code will look something like
this:
BEGIN
--
insert into generic_table
(a_col, another_col, yet_another_col)
values
(?,?,?);
--
COMMIT WRITE BATCH NOWAIT;
--
END;
I was looking for a way to do this but couldn't get it working in a test. The reason for my hold up was that I was expecting the wrong results from my test. I was testing by manually acquiring a shared table lock to simulate adding an index - but in this case, the insert query acquires the lock, not the commit. So it doesn't actually solve the problem I was looking to solve. I got round my problem by moving these insertions into a background queue, so that they don't hold up the main web request.
Anyway I think you can still do asynchronous commits in Hibernate. Basically you can use the Session.doWork() method to get access to the native Connection object (or in older versions of Hibernate, the Session.connection() method). I also moved the commit SQL into a strategy interface, so that we can run our HSQLDB-based tests which wouldn't understand the Oracle specific SQL.
In fact, it may be fine to use Session.createSQLQuery and give that the SQL, avoiding having to directly use Connection. Try it and see how it works.
private NativeStrategy nativeStrategy = new OracleStrategy();
interface NativeStrategy {
String commit();
}
public static final class OracleStrategy implements NativeStrategy {
public String commit() {
return "COMMIT WRITE BATCH NOWAIT";
}
}
public void saveAsynchronously(MyItem item) {
session.save(item);
session.flush();
// Try to issue an asynchronous commit where supported.
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
Statement commit = connection.createStatement();
try {
commit.execute( nativeStrategy.commit() );
} finally {
commit.close();
}
}
});
}

What is JDBC's Connection.isClosed() good for, and why is Snaq DBPool misbehaving on close?

I have the following code in Java:
if(!conn.isClosed())
{
conn.close();
}
Instead of working, I am awarded with:
java.sql.SQLException: Connection already closed
My connection object is a Snaq.db.CacheConnection
I checked the JavaDocs for isClosed, and they state that:
This method generally cannot be called
to determine whether a connection to a
database is valid or invalid. A
typical client can determine that a
connection is invalid by catching any
exceptions that might be thrown when
an operation is attempted.
So my questions are:
1) What good is JDBC's isClosed() anyway? Since when do we use Exceptions in Java to check for validity?
2) What is the correct pattern to close a database? Should I just close and swallow exceptions?
3) Any idea why would SnaqDB be closing the connection? (My backend is a Postgres 8.3)
I'll answer your questions with corresponding numbers:
I agree with you, it seems strange that isClosed provides the closed state only on a best effort basis, and that your code still has to be prepared to catch the exception when closing the connection. I think the reason is that the connection may be closed at any time by the database, and so any status returned by a query state method like isClosed is intrinsicly stale information - the state may change between checking isClosed and calling close on the Connection.
Calling close has no affect on your data and on previous queries. JDBC operations execute with synchronous results, so all useful execution has either succeeded or failed by the time isClosed is called. (True with both autoCommit or explicit transaction boundaries.) If your application is a single user accessing a local database, then perhaps showing the error to the user might help them diagnose problems. In other environments, logging the exception and swallowing it is probably the best course of action. Either way, swallowing the excpetion is safe, as has no bearing on the state of the database.
Looking at the source for SnaqDB CacheConnection, the isClosed method delegates to the underlying connection. So the problem is not there, but lies with the defined contract for isClosed() and Connection.close() throwing an exception.

TransactionScope, linq and strange transaction manager issue (HRESULT: 0x8004D024)

I have a service level methods, which make few changes to database and I want them to use transaction control. Such methods can do following:
- LINQ SubmitChanges() functionality
- Calls to StoredProcedures
Component users can combine set of such elementary operations into something bigger.
I see that there is nice class TransactinScope and trying to use it:
using (TransactionScope transaction = new TransactionScope())
{
content = repository.CreateBaseContent(content);
result = repository.CreateTreeRelation(content, parent.Id, name);
transaction.Complete();
}
public baseContent CreateBaseContent(baseContent content)
{
EntityContext.baseContents.InsertOnSubmit(content);
EntityContext.SubmitChanges();
return content;
}
public CreateTreeRelation (params)
{
// do StoredProcedure call here via LINQ
}
My Assumption was that on outer layers it would be possible to add another level of transaction scope. Instead, I am having following error:
The transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D024)
I am using same (Vista Ultimate) machine for MS SQL 2005 and microsoft development server. From unit tests everything works fine. Same when TransactionScope commented.
I was trying to play with security for DTC (http://support.microsoft.com/kb/899191) and when I set to acccept all inbound and outbound transactions, I have following error message:
Error HRESULT E_FAIL has been returned from a call to a COM component.
During debug, I discovered that in SubmitChanges, Linq Entity Context has Property Transaction IS NULL(!!), and System.Transactions.Transaction.Current has open transaction
I think you can also use TransactionScope as long as you pass the datacontexts the same connection you .Open.
Another issue you get with TransactionScope is that it doesn't care if the connection string is the same, doing a second .Open will elevate the transaction to a distributed transaction. And then you have to deal with the related configuration, and also the fact that it isn't using the light transaction that is what is needed for that case.
Issue happened because Linq Datacontext was created before transactionscope.
Solution was to add own transaction control to LINQ datacontext.
Connection.Open()
Transaction = Connection.BeginTransaction();
and counters to maintain nested calls.

Resources