I am having difficulty in reading data from my SQLite database from MonoTouch.
I can read and write without any difficulty for the first few screens and then suddenly I am unable to create any further connections with the error:
Mono.Data.Sqlite.SqliteException: Unable to open the database file
at Mono.Data.Sqlite.SQLite3.Open (System.String strFilename, SQLiteOpenFlagsEnum flags, Int32 maxPoolSize, Boolean usePool) [0x0007e] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs:136
at Mono.Data.Sqlite.SqliteConnection.Open () [0x002aa] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLiteConnection.cs:888
I ensure that i dispose and close every connection each time i use it but still i have this problem. For example:
var mySqlConn = new SqliteConnection(GlobalVars.connectionString);
mySqlConn.Open();
SqliteCommand mySqlCommand = new SqliteCommand(SQL, mySqlConn);
mySqlCommand.ExecuteNonQuery();
mySqlConn.Close();
mySqlCommand.Dispose();
mySqlConn.Dispose();
I'm guessing that I'm not closing the connections correctly. Any help would be greatly appreciated.
I'm pretty sure you guess is right. However it's pretty hard to guess what went wrong (e.g. what's defined in your connectionString will affect how Sqlite is initialized and will work).
From your example you seem to be disposing the SqliteConnection correctly but things could still go wrong. E.g. if some code throws an exception (and you catch them somewhere) then the Dispose call might never be called. It would be safer to do something like:
using (var mySqlConn = new SqliteConnection(GlobalVars.connectionString) {
mySqlConn.Open();
using (SqliteCommand mySqlCommand = new SqliteCommand(SQL, mySqlConn)) {
mySqlCommand.ExecuteNonQuery();
// work with the data
}
mySqlConn.Close();
}
That would ensure that the automagically finally clauses will dispose of the instance you create.
Also you might want to consider reusing your (first) connection instance, e.g. opening it once and re-use it everywhere in your application. OTOH you need to be aware of threading in this case (by default, you can change it, each connection is only safe to use on the thread that has created it).
Reusing could help your app performance but it also does not really fix your issue (but it might hide it). So I suggest you try to debug this first:
Using MonoDevelop you can set a breakpoint on line #136 on the /Developer/MonoTouch/Source/mono/mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLite3.cs file (which is included with your MonoTouch installation) to see the actual n error code (before it gets translated to a string).
You can also set breakpoints on the dispose code to ensure it gets executed (and does not return errors). The number of connection creations and disposals should match. If not then use the Call Stack to see who's opening without closing.
I would suggest using the "using" block..That will make sure that everything is disposed off correctly and also that you are not closing connections when it is already closed..
using (SqliteConnection conn = new SqliteConnection(GlobalVars.connectionString))
{
conn.Open ();
SqliteCommand command = new SqliteCommand (conn);
.............
}
OK - i've got it working now by moving the close and dispose into a "finally".
var mySqlConn = new SqliteConnection (GlobalVars.connectionString);
mySqlConn.Open ();
try {
// CODE HERE
} finally {
mySqlConn.Close();
mySqlConn.Dispose();
}
Related
I need a to get a bit of understanding in this, When you open a connection to a Database can you leave it open?
How does this connection close?
Is it good practise or bad practice?
Currently I have a request to a database that works no problem
oCON.Open();
oCMD.ExecuteNonQuery();
oCON.Close();
However Some of the examples that I have seen are something like this with no database close.
oCON.Open();
oCMD.ExecuteNonQuery();
How would this connection get closed?
Is this bad practice?
I was looking for a duplicate, as this seems to be a common question. The top answer I found is this one, however, I don't like the answer that was given.
You should always close your connection as soon as you're done with it. The database has a finite number of connections that it allows, and it also takes a lot of resources.
The "old school" way to ensure the close occurred was with a try/catch/finally block:
SqlConnection connection;
SqlCommand command;
try
{
// Properly fill in all constructor variables.
connection = new SqlConnection();
command = new SqlCommand();
connection.Open();
command.ExecuteNonQuery();
// Parse the results
}
catch (Exception ex)
{
// Do whatever you need with exception
}
finally
{
if (connection != null)
{
connection.Dispose();
}
if (command != null)
{
command.Dispose();
}
}
However, the using statement is the preferred way as it will automatically Dispose of the object.
try
{
using (var connection = new SqlConnection())
using (var command = new SqlCommand())
{
connection.Open();
command.ExecuteNonQuery();
// Do whatever else you need to.
}
}
catch (Exception ex)
{
// Handle any exception.
}
The using statement is special in that even if an exception gets thrown, it still disposes of the objects that get created before the execution of the code stops. It makes your code more concise and easier to read.
As mentioned by christophano in the comments, when your code gets compiled down to IL, it actually gets written as a try/finally block, replicating what is done in the above example.
You want your SqlConnection to be in a using block:
using(var connection = new SqlConnection(connectionString))
{
...
}
That ensures that the SqlConnectionwill be disposed, which also closes it.
From your perspective the connection is closed. Behind the scenes the connection may or may not actually be closed. It takes time and resources to establish a SQL connection, so behind the scenes those connections aren't immediately closed. They're kept open and idle for a while so that they can be reused. It's called connection pooling. So when you open a connection, you might not really be opening a new connection. You might be retrieving one from the connection pool. And when you close it, it doesn't immediately close, it goes back to the pool.
That's all handled behind the scenes and it doesn't change what we explicitly do with our connections. We always "close" them as quickly as possible, and then the .NET Framework determines when they actually get closed. (It's possible to have some control over that behavior but it's rarely necessary.)
Take a look at the Repository Pattern with Unit of Work.
A connection context should be injected into the class which operates commands to the database.
A sql execution class - like a repository class represents - should not create a connection. It is not testable and hurts the paradigm of SRP.
It should accept an IDbConnection object like in the constructor. The repository should not take care if behind the IDbConnection is an instance of SqlConnection, MysqlConnection or OracleConnection.
All of the ADO.NET connection objects are compatible to IDbConnection.
Some first things that people learned in their early use of MySQL that closing connection right after its usage is important, but why is this so important? Well, if we do it on a website it can save some server resource (as described here) But why we should do that on a .NET desktop application? Does it share the same issues with web application? Or are there others?
If you use connection pooling you won't close the physical connection by calling con.Close, you just tell the pool that this connection can be used. If you call database stuff in a loop you'll get exceptions like "too many open connections" quickly if you don't close them.
Check this:
for (int i = 0; i < 1000; i++)
{
var con = new SqlConnection(Properties.Settings.Default.ConnectionString);
con.Open();
var cmd = new SqlCommand("Select 1", con);
var rd = cmd.ExecuteReader();
while (rd.Read())
Console.WriteLine("{0}) {1}", i, rd.GetInt32(0));
}
One of the possible exceptions:
Timeout expired. The timeout period elapsed prior to obtaining a
connection from the pool. This may have occurred because all pooled
connections were in use and max pool size was reached.
By the way, the same is true for a MySqlConnection.
This is the correct way, use the using statement on all types implementing IDsiposable:
using (var con = new SqlConnection(Properties.Settings.Default.ConnectionString))
{
con.Open();
for (int i = 0; i < 1000; i++)
{
using(var cmd = new SqlCommand("Select 1", con))
using (var rd = cmd.ExecuteReader())
while (rd.Read())
Console.WriteLine("{0}) {1}", i, rd.GetInt32(0));
}
}// no need to close it with the using statement, will be done in connection.Dispose
Yes I think it is important to close out your connection rather than leaving it open or allowing the garbage collector to eventually handle it. There are a couple of reason why you should do this and below that I'll describe the best method for how
WHY:
So you've opened a connection to the database and sent some data back and forth along this pipeline and now have the results you were looking for. Ideally at this point you do something else with the data and the end results of your application is achieved.
Once you have the data from the database you don't need it anymore, its part in this is done so leaving the connection open does nothing but hold up memory and increase the number of connections the database and your application has to keep track of and possibly pushing you closer to your maximum number of connections limit.
"But wait! I have to make a lot of database calls in rapid
succession!"
Okay no problem, open the connection run your calls and then close it out again. Opening a connection to a database in a "modern" application isn't going to cost you a significant amount of computing power/time, while explicitly closing out a connection does nothing but help (frees up memory, lowers your number of current connections).
So that is the why, here is the how
HOW:
So depending on how you are connecting to your MySQL database you a probably using an IDisposible object to help manage the connection. Here is what MSDN has to say on using an IDisposable:
As a rule, when you use an IDisposable object, you should declare and
instantiate it in a using statement. The using statement calls the
Dispose method on the object in the correct way, and (when you use it
as shown earlier) it also causes the object itself to go out of scope
as soon as Dispose is called. Within the using block, the object is
read-only and cannot be modified or reassigned.
Here is my personal take on the subject:
Using a using block helps to keep your code cleaner (readability)
Using a usingblock helps to keep your code clear (memory wise), it will "automagically" clean up unused items
With a usingblock it helps to prevent using a previous connection from being used accidentally as it will automatically close out the connection when you are done with it.
In short, I think it is important to close connections properly, preferably with a con.close() type statement method in combination with a using block
As pointed out in the comments this is also a very good question/answer similar to yours: Why always close Database connection?
I'm working on an ASP.NET application where, as part of some logic, I want to lock some tables and do work on them. The method runs in a separate thread running as a kind of background task, spawned via a Task. The problem comes in with the error handling...
The code looks more or less like this:
MySqlConnection connection = new MySqlConnection(ConfigurationManager.AppSettings["prDatabase"]);
try
{
connection.Open();
MySqlCommand lock_tables = new MySqlCommand(Queries.lockTables(), connection);
lock_tables.ExecuteNonQuery();
// do a bunch of work here
MySqlCommand unlock_tables = new MySqlCommand(Queries.unlockTables(), connection);
unlock_tables.ExecuteNonQuery();
}
catch (MySqlException mex)
{
// Mostly error logging here
}
finally
{
connection.Close();
}
Pretty simple stuff. Everything works fine and dandy assuming nothing goes wrong. That's a terrible assumption to make, though, so I deliberately set up a situation where things would foul up in the middle and move to the finally block.
The result was that my table locks remained until I closed the app, which I learned by trying to access the tables with a different client once the method completed. Needless to say this isn't my intention, especially since there's another app that's supposed to access those tables once I'm done with them.
I could quickly fix the problem by explicitly releasing the locks before closing the connection, but I'm still left curious about some things. Everything I've read before has sworn that closing a connection should implicitly release the table locks. Obviously in this case it isn't. Why is that? Does connection.Close() not actually completely close the connection? Is there a better way I should be closing my connections?
Try wrapping your Connection and MySqlCommand instance in a using statement. That will release the objects as soon as it leaves the brackets.
using(MySqlConnection conn = new MySqlConnection(connStr))
{
conn.Open();
using(MySqlCommand command = new MySqlCommand("command to execute",conn))
{
//Code here..
}
}
I have the following code:
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;")
{
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection))
{
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.BeginExecuteNonQuery();
}
}
I never call EndExecuteNonQuery.
Two questions, first will this block because of the using statements or any other reason? Second, will it break anything? Like leaks or connection problems? I just want to tell sql server to run a stored procedure, but I don't want to wait for it and I don't even care if it works. Is that possible? Thanks for reading.
This won't work because you're closing the connection while the query is still running. The best way to do this would be to use the threadpool, like this:
ThreadPool.QueueUserWorkItem(delegate {
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;") {
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection)) {
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.ExecuteNonQuery();
}
}
});
In general, when you call Begin_Whatever_, you usually must call End_Whatever_ or you'll leak memory. The big exception to this rule is Control.BeginInvoke.
You can't close the connection after you submit the BeginExceuteNotQuery. It will abort the execution. Remove the using block.
In order to close the connection, you must know when the call has completed. For that you must call EndExecuteNonQuery, usually from a callback:
.
command.BeginExecuteNonQuery(delegate (IAsyncResult ar) {
try { command.EndExecuteNonQuery(ar); }
catch(Exception e) { /* log exception e */ }
finally { sqlConnection.Dispose(); }
}, null);
If you want to submit a query and don't care about the results, see Asynchronous T-SQL execution for a reliable pattern that ensures execution even if client diconnects or crashes.
You should always call the EndExecuteNonQuery() method to prevent leaks. It may work now but who knows what will happen in future versions of .NET. The general rule is always follow a BeginExecute... with an EndExecute...
I know this is an old post; just adding my 2c based on our recent (very conclusive) implementation and testing :D
To answer the OP's questions:
If you don't call EndExecuteNonQuery, BeginExecuteNonQuery will execute the procedure, but the operation will be cancelled as soon as the using clause disposes of your sql connection. Hence this is not plausible.
If you call BeginExecuteNonQuery by using a delegate, creating a new thread etc and you do not call EndExecuteNonQuery, chances are good you might get memory leaks depending on what takes place in you stored procedure. (More on this later).
Calling an stored procedure and not waiting for the call to complete, as far I our testing went, is not possible. Irrespective of multitasking, something somewhere will have to wait.
On to our solution:
Refs: BeginExecuteNonQuery -> BENQ, EndExecuteNonQuery -> EENQ
Use Case:
We have a windows service (C#) that makes use of the .Net TPL library. We needed to load data with a stored procedure from one database to another at run time, based on a add hoc request that the service picks up. Our stored procedure had an internal transaction and exception handling with try catch blocks.
First Try:
For our first try we implemented a solution found here MS Solution in this example you will see that MS opts to call BENQ then implements a while loop to block execution and then calls EENQ. This solution was mainly implemented if you don't need a callback method. The problem with this solution is that only BENQ is ignorant to sql connection timeouts. EENQ will timeout. So for a long running query (which is hopefully the reason why you are using BENQ) you will get stuck in the while and once the operation has completed and you call EENQ, you will get an sql timeout connection.
Second Try:
For our second try we thought ok so lets call BENQ, then add a while so that we don't close our sql connection and never call EENQ. This worked, until an exception was thrown in our stored procedure. Because we never called EENQ, the operation was never completed and the exception never bubbled up to our code. Hence we were stuck in a loop/thread/memory leak forever.
Third Try: (The Solution)
For our third try we thought to call BENQ, then directly after call EENQ. What happened was that EENQ effectively blocked execution in the thread until the operation completed. When an exception occurred in the stored procedure it was caught. When the query ran long EENQ did not throw a timeout exception and in all cases our sql connection object was disposed as well as our thread.
Here are some extracts of our code:
Here we open up a new thread for the method that calls the stored procedure.
//Call the load data stored procedure. As this stored procedure can run longer we start it in its own thread.
Task.Factory.StartNew(() => ClassName.MethodName(Parameters));
This is the code inside the method we use to call the stored procedure.
//Because this is a long running stored procedure, we start is up in a new thread.
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ConnectionStringName"]].ConnectionString))
{
try
{
//Create a new instance SqlCommand.
SqlCommand command = new SqlCommand(ConfigurationManager.AppSettings["StoredProcedureName"], conn);
//Set the command type as stored procedure.
command.CommandType = CommandType.StoredProcedure;
//Create input parameters.
command.Parameters.Add(CreateInputParam("#Param1", SqlDbType.BigInt, Param1));
command.Parameters.Add(CreateInputParam("#Param2", SqlDbType.BigInt, Param3));
command.Parameters.Add(CreateInputParam("#Param3", SqlDbType.BigInt, Param3));
//Open up the sql connection.
conn.Open();
//Create a new instance of type IAsyncResult and call the sp asynchronously.
IAsyncResult result = command.BeginExecuteNonQuery();
//When the process has completed, we end the execution of the sp.
command.EndExecuteNonQuery(result);
}
catch (Exception err)
{
//Write to the log.
}
}
I hope this answer save's someone some headache :D We have tested this thoroughly and have not experienced any issues.
Happy coding!
In this case the using statements won't be necessary because you should manually close it yourself rather than allowing the syntactic sugar dispose it for you (i.e. at the }).
It should be as simple as this to ensure you don't have leaks.
using (SqlConnection sqlConnection = new SqlConnection("blahblah;Asynchronous Processing=true;")
{
using (SqlCommand command = new SqlCommand("someProcedureName", sqlConnection))
{
sqlConnection.Open();
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#param1", param1);
command.BeginExecuteNonQuery((ar) =>
{
var cmd = (SqlCommand)ar.AsyncState;
cmd.EndExecuteNonQuery(ar);
cmd.Connection.Close();
}, command);
}
}
As you can see the lambda expression that is fired once the command is finished (no matter how long it takes) will do all the closing for you.
I'm performing a large number of INSERTS to a SQLite database. I'm using just one thread. I batch the writes to improve performance and have a bit of security in case of a crash. Basically I cache up a bunch of data in memory and then when I deem appropriate, I loop over all of that data and perform the INSERTS. The code for this is shown below:
public void Commit()
{
using (SQLiteConnection conn = new SQLiteConnection(this.connString))
{
conn.Open();
using (SQLiteTransaction trans = conn.BeginTransaction())
{
using (SQLiteCommand command = conn.CreateCommand())
{
command.CommandText = "INSERT OR IGNORE INTO [MY_TABLE] (col1, col2) VALUES (?,?)";
command.Parameters.Add(this.col1Param);
command.Parameters.Add(this.col2Param);
foreach (Data o in this.dataTemp)
{
this.col1Param.Value = o.Col1Prop;
this. col2Param.Value = o.Col2Prop;
command.ExecuteNonQuery();
}
}
this.TryHandleCommit(trans);
}
conn.Close();
}
}
I now employ the following gimmick to get the thing to eventually work:
private void TryHandleCommit(SQLiteTransaction trans)
{
try
{
trans.Commit();
}
catch (Exception e)
{
Console.WriteLine("Trying again...");
this.TryHandleCommit(trans);
}
}
I create my DB like so:
public DataBase(String path)
{
//build connection string
SQLiteConnectionStringBuilder connString = new SQLiteConnectionStringBuilder();
connString.DataSource = path;
connString.Version = 3;
connString.DefaultTimeout = 5;
connString.JournalMode = SQLiteJournalModeEnum.Persist;
connString.UseUTF16Encoding = true;
using (connection = new SQLiteConnection(connString.ToString()))
{
//check for existence of db
FileInfo f = new FileInfo(path);
if (!f.Exists) //build new blank db
{
SQLiteConnection.CreateFile(path);
connection.Open();
using (SQLiteTransaction trans = connection.BeginTransaction())
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = DataBase.CREATE_MATCHES;
command.ExecuteNonQuery();
command.CommandText = DataBase.CREATE_STRING_DATA;
command.ExecuteNonQuery();
//TODO add logging
}
trans.Commit();
}
connection.Close();
}
}
}
I then export the connection string and use it to obtain new connections in different parts of the program.
At seemingly random intervals, though at far too great a rate to ignore or otherwise workaround this problem, I get unhandled SQLiteException: Database file is locked. This occurs when I attempt to commit the transaction. No errors seem to occur prior to then. This does not always happen. Sometimes the whole thing runs without a hitch.
No reads are being performed on these files before the commits finish.
I have the very latest SQLite binary.
I'm compiling for .NET 2.0.
I'm using VS 2008.
The db is a local file.
All of this activity is encapsulated within one thread / process.
Virus protection is off (though I think that was only relevant if you were connecting over a network?).
As per Scotsman's post I have implemented the following changes:
Journal Mode set to Persist
DB files stored in C:\Docs + Settings\ApplicationData via System.Windows.Forms.Application.AppData windows call
No inner exception
Witnessed on two distinct machines (albeit very similar hardware and software)
Have been running Process Monitor - no extraneous processes are attaching themselves to the DB files - the problem is definitely in my code...
Does anyone have any idea whats going on here?
I know I just dropped a whole mess of code, but I've been trying to figure this out for way too long. My thanks to anyone who makes it to the end of this question!
brian
UPDATES:
Thanks for the suggestions so far! I've implemented many of the suggested changes. I feel that we are getting closer to the answer...however...
The code above technically works however it is non-deterministic! It is not guaranteed to do anything aside from spin in neutral forever. In practice it seems to work somewhere between the 1st and 10th iteration. If i batch my commits at a reasonable interval damage will be mitigated but I really do not want to leave things in this state...
More suggestions welcome!
It looks like you failed to link the command with the transaction you've created.
Instead of:
using (SQLiteCommand command = conn.CreateCommand())
You should use:
using (SQLiteCommand command = new SQLiteCommand("<INSERT statement here>", conn, trans))
Or you can set its Transaction property after its construction.
While we are at it - your handling of failures is incorrect:
The command's ExecuteNonQuery method can also fail and you are not really protected. You should change the code to something like:
public void Commit()
{
using (SQLiteConnection conn = new SQLiteConnection(this.connString))
{
conn.Open();
SQLiteTransaction trans = conn.BeginTransaction();
try
{
using (SQLiteCommand command = conn.CreateCommand())
{
command.Transaction = trans; // Now the command is linked to the transaction and don't try to create a new one (which is probably why your database gets locked)
command.CommandText = "INSERT OR IGNORE INTO [MY_TABLE] (col1, col2) VALUES (?,?)";
command.Parameters.Add(this.col1Param);
command.Parameters.Add(this.col2Param);
foreach (Data o in this.dataTemp)
{
this.col1Param.Value = o.Col1Prop;
this. col2Param.Value = o.Col2Prop;
command.ExecuteNonQuery();
}
}
trans.Commit();
}
catch (SQLiteException ex)
{
// You need to rollback in case something wrong happened in command.ExecuteNonQuery() ...
trans.Rollback();
throw;
}
}
}
Another thing is that you don't need to cache anything in memory. You can depend on SQLite journaling mechanism for storing incomplete transaction state.
Run Sysinternals Process Monitor and filter on filename while running your program to rule out if any other process does anything to it and to see what exacly your program is doing to the file. Long shot, but might give a clue.
We had a very similar problem using nested Transactions with the TransactionScope class. We thought all database actions occurred on the same thread...however we were caught out by the Transaction mechanism...more specifically the Ambient transaction.
Basically there was a transaction higher up the chain which, by the magic of ado, the connection automatically enlisted in. The result was that, even though we thought we were writing to the database on a single thread, the write didn't really happen until the topmost transaction was committed. At this 'indeterminate' point the database was written to causing it to be locked outside of our control.
The solution was to ensure that the sqlite database did not directly take part in the ambient transaction by ensuring we used something like:
using(TransactionScope scope = new TransactionScope(TransactionScopeOptions.RequiresNew))
{
...
scope.Complete()
}
Things to watch for:
don't use connections across multiple threads/processes.
I've seen it happen when a virus scanner would detect changes to the file and try to scan it. It would lock the file for a short interval and cause havoc.
I started facing this same problem today: I'm studying asp.net mvc, building my first application completely from scratch. Sometimes, when I'd write to the database, I'd get the same exception, saying the database file was locked.
I found it really strange, since I was completely sure that there was just one connection open at that time (based on process explorer's listing of active file handles).
I've also built the whole data access layer from scratch, using System.Data.SQLite .Net provider, and, when I planned it, I took special care with connections and transactions, in order to ensure no connection or transaction was left hanging around.
The tricky part was that setting a breakpoint on ExecuteNonQuery() command and running the application in debug mode would make the error disappear!
Googling, I found something interesting on this site: http://www.softperfect.com/board/read.php?8,5775. There, someone replied the thread suggesting the author to put the database path on the anti-virus ignore list.
I added the database file to the ignore list of my anti-virus (Microsoft Security Essentials) and it solved my problem. No more database locked errors!
Is your database file on the same machine as the app or is it stored on a server?
You should create a new connection in every thread. I would simplefy the creation of a connection, use everywhere: connection = new SQLiteConnection(connString.ToString());
and use a database file on the same machine as the app and test again.
Why the two different ways of creating a connection?
These guys were having similiar problems (mostly, it appears, with the journaling file being locked, maybe TortoiseSVN interactions ... check the referenced articles).
They came up with a set of recommendations (correct directories, changing journaling types from delete to persist, etc). http://sqlite.phxsoftware.com/forums/p/689/5445.aspx#5445
The journal mode options are discussed here: http://www.sqlite.org/pragma.html . You could try TRUNCATE.
Is there a stack trace during the exception into SQL Lite?
You indicate you "batch my commits at a reasonable interval". What is the interval?
I would always use a Connection, Transaction and Command in a using clause. In your first code listing you did, but your third (creating the tables) you didn't. I suggest you do that too, because (who knows?) maybe the commands that create the table somehow continue to lock the file. Long shot... but worth a shot?
Do you have Google Desktop Search (or another file indexer) running? As previously mentioned, Sysinternals Process Monitor can help you track it down.
Also, what is the filename of the database? From PerformanceTuningWindows:
Be VERY, VERY careful what you name your database, especially the extension
For example, if you give all your databases the extension .sdb (SQLite Database, nice name hey? I thought so when I choose it anyway...) you discover that the SDB extension is already associated with APPFIX PACKAGES.
Now, here is the cute part, APPFIX is an executable/package that Windows XP recognizes, and it will, (emphasis mine) ADD THE DATABASE TO THE SYSTEM RESTORE FUNCTIONALITY
This means, stay with me here, every time you write ANYTHING to the database, the Windows XP system thinks a bloody executable has changed and copies your ENTIRE 800 meg database to the system restore directory....
I recommend something like DB or DAT.
While the lock is reported on the COMMIT, the lock is on the INSERT/UPDATE command. Check for record locks not being released earlier in your code.