在我们的一个Java应用程序中,我们有一个SQLite DB,多个线程读写同一个DB(不同的表)。然而,这些多线程使用相同的数据库连接对象(ORMLite的DaoManager.createDao())。
每当执行某些insert / update语句时,我们都会随机获取此SQLException(Resultset已请求)。下面是一个这样的实例的堆栈跟踪。
java.sql.SQLException: Unable to run insert stmt on object ABCD-164: INSERT INTO `pos_order` (`bill_number` ,`order_status` ,`order_type` ,`payment_mode` ,`reference_bill_number` ,`table_selected` ,`sub_total` ,`discountable_sub_total` ,`total` ,`total_discount` ,`discount_type` ,`discount_value` ,`total_tax` ,`service_charge` ,`service_tax` ,`vat` ,`delivery_charge` ,`packaging_charge` ,`amount_paid` ,`waiter` ,`delivery_boy` ,`order_source` ,`delivery_source` ,`card_type` ,`card_name` ,`client_creation_time` ,`client_updation_time` ,`order_comment` ,`customer_feedback` ,`is_deleted` ,`payment_status` ,`pos_outlet_id` ,`is_sync` ,`delivery_status` ,`shipment_id` ,`response_code` ,`delivery_time` ,`custom_packaging_charge_enable` ,`custom_delivery_charge_enable` ,`receipt_printed` ,`total_person` ,`order_origin` ,`json` ,`oo_system_id` ,`pre_order` ,`pre_order_time` ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
at com.j256.ormlite.misc.SqlExceptionUtil.create(SqlExceptionUtil.java:22)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:135)
at com.j256.ormlite.stmt.StatementExecutor.create(StatementExecutor.java:450)
at com.j256.ormlite.dao.BaseDaoImpl.create(BaseDaoImpl.java:310)
at com.j256.ormlite.dao.BaseDaoImpl.createOrUpdate(BaseDaoImpl.java:336)
at com.limetray.pos.dbmanagers.implementations.PosOrderDaoImpl.insert(PosOrderDaoImpl.java:50)
at com.limetray.pos.controllers.BillingSectionController.lambda$10(BillingSectionController.java:808)
at com.limetray.pos.utilities.SingleTaskExecutor$1.call(SingleTaskExecutor.java:37)
at javafx.concurrent.Task$TaskCallable.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: ResultSet already requested
at org.sqlite.jdbc3.JDBC3Statement.getResultSet(JDBC3Statement.java:136)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeQuery(JDBC3PreparedStatement.java:69)
at org.sqlite.jdbc3.JDBC3DatabaseMetaData.getGeneratedKeys(JDBC3DatabaseMetaData.java:1796)
at org.sqlite.jdbc3.JDBC3Statement.getGeneratedKeys(JDBC3Statement.java:346)
at com.j256.ormlite.jdbc.JdbcDatabaseConnection.insert(JdbcDatabaseConnection.java:173)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:91)
... 13 more
非常感谢任何帮助。感谢。
答案 0 :(得分:3)
在我们的一个Java应用程序中,我们有一个SQLite数据库,多个线程读写同一个数据库(不同的表)。
使用SQLite数据库,您一次只能有一个连接。数据库具有内部锁定,可确保没有两个线程同时使用相同的连接,但这并不会阻止DAO允许多个线程导致您遇到的问题。
Caused by: java.sql.SQLException: ResultSet already requested
在您的情况下,由于多个线程正在使用相同的连接,当一个线程在已经被我的另一个线程询问的连接上请求结果时,会抛出此异常。他们的查询不正确地被交错。
认识到这与底层数据库无关是很重要的。 Sqlite有自己的锁,可以阻止多个线程的并发访问。但在这种情况下,我们遇到了使用相同连接的多个线程的问题。
现在,ORMLite没有ConnectionSource
提供与基础数据库的synchronized
单一连接,因此您必须自己进行外部锁定。您可以扩展JdbcSingleConnectionSource
class并使用ReentrantLock
来强制执行控制。也许是这样的:
public class LockedJdbcSingleConnectionSource extends JdbcSingleConnectionSource {
private final ReentrantLock lock = new ReentrantLock();
// called from JdbcSingleConnectionSource.getReadOnlyConnection() ...
public DatabaseConnection getReadWriteConnection() {
lock.lock();
return super.getReadWriteConnection();
}
public void releaseConnection(DatabaseConnection connection) {
super.releaseConnection(connection);
lock.unlock();
}
}