Question

I have made a Java program that connects to a SQLite database using SQLite4Java.

I read from the serial port and write values to the database. This worked fine in the beginning, but now my program has grown and I have several threads. I have tried to handle that with a SQLiteQueue-variable that execute database operations with something like this:

public void insertTempValue(final SQLiteStatement stmt, final long logTime, final double tempValue)
{
    if(checkQueue("insertTempValue(SQLiteStatement, long, double)", "Queue is not running!", false))
    {
        queue.execute(new SQLiteJob<Object>()
                {
                    protected Object job(SQLiteConnection connection) throws SQLiteException
                    {
                        stmt.bind(1, logTime);
                        stmt.bind(2, tempValue);

                        stmt.step();
                        stmt.reset(true);

                        return null;
                    }
                });
    }
} // end insertTempValue(SQLiteStatement, long, double)

But now my SQLite-class can't execute the statements reporting :

DB[1][U]: disposing [INSERT INTO Temperatures VALUES (?,?)]DB[1][U] from alien thread
SQLiteDB$6@8afbefd: job exception com.almworks.sqlite4java.SQLiteException: [-92] statement is disposed

So the execution does not happen.

I have tried to figure out what's wrong and I think I need a Java wrapper that makes all the database operations calls from a single thread that the other threads go through.

Here is my problem I don't know how to implement this in a good way. How can I make a method-call and ensure that it always runs from the same thread?

Was it helpful?

Solution 2

I found a solution to my problem. I have now implemented a wrapper-class that makes all operations with my older SQLite-class using an ExecutorService, inspired from Thread Executor Example and got the correct usage from Java Doc ExecutorService.

OTHER TIPS

Put all your database access code into a package and make all the classes package private. Write one Runnable or Thread subclass with a run() method that runs a loop. The loop checks for queued information requests, and runs the appropriate database access code to find the information, putting the information into the request and marking the request complete before going back to the queue.

Client code queues data requests and waits for answers, perhaps by blocking until the request is marked complete.

Data requests would look something like this:

public class InsertTempValueRequest {

    // This method is called from client threads before queueing
    // Client thread queues this object after construction
    public InsertTempValueRequest(
        final long logTime,
        final double tempValue
    ) {
         this.logTime = logTime
         this.tempValue = tempValue
    }

    // This method is called from client threads after queueing to check for completion
    public isComplete() {
        return isComplete;
    }

    // This method is called from the database thread after dequeuing this object
    execute(
        SQLiteConnection connection,
        SQLiteStatement statement
    ) {
        // execute the statement using logTime and tempValue member data, and commit

        isComplete = true;
    }

    private volatile long logTime;
    private volatile double tempValue;
    private volatile boolean isComplete = false;
}

This will work, but I suspect there will be a lot of hassle in the implementation. I think you could also get by by using a lock that only permits one thread at a time to access the database, and also - this is the difference from your existing situation - beginning the access by creating the database resources - including statements - from scratch, and disposing of those resources before releasing the lock.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top