You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX TableView数据批量存入SQLite遇文件锁错误求助

问题描述

开发商店管理应用时,新产品先在TableView中展示,再存入数据库。用List<Product>给TableView添加数据显示正常,但调用addBatch()和executeBatch()批量插入SQLite时触发数据库文件锁错误,已经设置autocommit=false。尝试循环插入时,要么数据库无变化,要么同样触发文件锁问题。

批量插入代码

public void validerFacture() throws SQLException {
    String ajoutProduits = BaseDeDonne.AJOUTER_PRODUITS;
    Connection connection = null;
    PreparedStatement ps = null;
    try {
        connection = BaseDeDonne.connect();
        connection.setAutoCommit(false);
        ps = connection.prepareStatement(ajoutProduits);
        for (Produits p : produits) {
            ps.setInt(1, p.getQuantite());
            ps.setString(2, p.getCategorie());
            ps.setString(3, p.getTaille());
            ps.setString(4, p.getDesignation());
            ps.setDouble(5, p.getPrixEnGros());
            ps.setDouble(6, p.getPrixUnitaire());
            ps.setDouble(7, p.getPrixVente());
            ps.setDouble(8, p.getMarge());
            ps.addBatch();
        }
        ps.executeBatch();
        connection.commit();

    } catch (SQLException b) {
        b.printStackTrace();
    } 
}

插入SQL语句

public static final String AJOUTER_PRODUITS = "INSERT INTO " + TABLE_PRODUIT + "("
            + COLUMN_PRODUIT_QUANTITE + ","
            + COLUMN_PRODUIT_CATEGORIE+ ","
            + COLUMN_PRODUIT_TAILLE + ","
            + COLUMN_PRODUIT_DESIGANTION + ","
            + COLUMN_PRODUIT_PRIX_ACHAT + ","
            + COLUMN_PRODUIT_PRIX_REVIENT + ","
            + COLUMN_PRODUIT_PRIX_VENTE + ","
            + COLUMN_PRODUIT_PRIX_MARGE
              +")"
            + " VALUES " +
            "(" + "?" + "," + "?" + "," + "?" + "," + "?" + "," + "?" + "," + "?" + "," + "?" + "," + "?" + ")";
解决方案

1. 强制关闭资源,避免锁泄漏

SQLite对连接和语句的资源泄漏极度敏感,必须在finally块中按顺序关闭PreparedStatement和Connection,否则会导致文件锁无法释放。同时出错时要回滚事务:

public void validerFacture() throws SQLException {
    String ajoutProduits = BaseDeDonne.AJOUTER_PRODUITS;
    Connection connection = null;
    PreparedStatement ps = null;
    try {
        connection = BaseDeDonne.connect();
        connection.setAutoCommit(false);
        ps = connection.prepareStatement(ajoutProduits);
        for (Produits p : produits) {
            ps.setInt(1, p.getQuantite());
            ps.setString(2, p.getCategorie());
            ps.setString(3, p.getTaille());
            ps.setString(4, p.getDesignation());
            ps.setDouble(5, p.getPrixEnGros());
            ps.setDouble(6, p.getPrixUnitaire());
            ps.setDouble(7, p.getPrixVente());
            ps.setDouble(8, p.getMarge());
            ps.addBatch();
        }
        ps.executeBatch();
        connection.commit();
    } catch (SQLException b) {
        if (connection != null) {
            try {
                connection.rollback(); // 出错时回滚,避免脏数据
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        b.printStackTrace();
    } finally {
        // 先关Statement,再关Connection,顺序不能乱
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

2. 拆分大批次为小批量

SQLite单批次操作数量过大时,会延长锁持有时间引发冲突。可以每50条执行一次批次:

int batchSize = 50;
int count = 0;
for (Produits p : produits) {
    // 设置参数...
    ps.addBatch();
    count++;
    if (count % batchSize == 0) {
        ps.executeBatch();
        ps.clearBatch(); // 清空已执行的批次
    }
}
// 执行剩余的未达批次大小的数据
if (count % batchSize != 0) {
    ps.executeBatch();
}

3. 检查连接获取逻辑

如果BaseDeDonne.connect()返回的是单例连接,或者连接池配置错误,会导致多个操作共享连接引发锁冲突。确保每次获取独立的新连接,或者配置连接池的超时、释放机制。

4. 核对字段映射

检查实体类属性和数据库字段的对应关系:比如代码中ps.setDouble(5, p.getPrixEnGros())对应SQL里的COLUMN_PRODUIT_PRIX_ACHAT,ps.setDouble(6, p.getPrixUnitaire())对应COLUMN_PRODUIT_PRIX_REVIENT,必须完全匹配,否则可能出现插入失败但无异常的情况,导致事务未提交。

5. 排除外部占用

确保没有其他工具(如SQLite浏览器)打开数据库文件,也没有其他线程同时对数据库执行写操作——SQLite的写锁是排他锁,同一时间只能有一个写操作。

内容的提问来源于stack exchange,提问作者aboubacry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:43:13