1

我制作了一个使用 SQLite4Java 连接到 SQLite 数据库的 Java 程序。

我从串行端口读取并将值写入数据库。这在开始时效果很好,但现在我的程序已经增长并且我有几个线程。我试图用一个 SQLiteQueue 变量来处理这个问题,该变量执行数据库操作,如下所示:

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)

但现在我的 SQLite 类无法执行报表报告:

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

所以执行不会发生。

我试图找出问题所在,我认为我需要一个 Java 包装器,它可以从其他线程通过的单个线程进行所有数据库操作调用。

这是我的问题,我不知道如何以一种好的方式实现它。如何进行方法调用并确保它始终从同一个线程运行?

4

2 回答 2

1

将所有数据库访问代码放入一个包中,并将所有类包设为私有。使用运行循环的 run() 方法编写一个 Runnable 或 Thread 子类。循环检查排队的信息请求,并运行适当的数据库访问代码来查找信息,将信息放入请求中并在返回队列之前标记请求完成。

客户端代码将数据请求排队并等待答案,可能会阻塞直到请求被标记为完成。

数据请求看起来像这样:

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;
}

这会起作用,但我怀疑在实施过程中会有很多麻烦。我认为你也可以通过使用一次只允许一个线程访问数据库的锁来解决问题,而且 - 这与你现有的情况不同 - 通过从头开始创建数据库资源 - 包括语句来开始访问,并在释放锁之前处理这些资源。

于 2014-04-22T02:56:13.457 回答
0

我找到了解决我的问题的方法。我现在已经实现了一个包装类,它使用 ExecutorService 对我的旧 SQLite 类进行所有操作,灵感来自Thread Executor Example并从Java Doc ExecutorService获得了正确的用法。

于 2014-04-27T10:17:59.840 回答