Java 如何在并发批处理中绕过JDBC语句缓存?

Java 如何在并发批处理中绕过JDBC语句缓存?,java,jdbc,prepared-statement,Java,Jdbc,Prepared Statement,我正在开发一个服务器,它可以接收数百个业务部门的夜间报告。报告当前是加密的csv文件。总的来说,这些报告每天应该有500000到1000000条记录保存到数据库中供以后使用 我已经为每次传输创建了一组PreparedStatements。这些语句用于在执行和提交之前批处理50条记录。每个记录最多可导致20个数据库插入。当传输排队并逐个处理时,一切正常 当我同时尝试这样做时,我注意到不同的线程得到了完全相同的PreparedStatements实例。这导致了以下问题 多个线程向同一批添加了语句 当

我正在开发一个服务器,它可以接收数百个业务部门的夜间报告。报告当前是加密的csv文件。总的来说,这些报告每天应该有500000到1000000条记录保存到数据库中供以后使用

我已经为每次传输创建了一组PreparedStatements。这些语句用于在执行和提交之前批处理50条记录。每个记录最多可导致20个数据库插入。当传输排队并逐个处理时,一切正常

当我同时尝试这样做时,我注意到不同的线程得到了完全相同的PreparedStatements实例。这导致了以下问题

  • 多个线程向同一批添加了语句
  • 当任何线程决定执行批处理时,批处理正在执行
  • 当数据库不满足其约束条件时调用Commit,因为某些线程没有时间使用某些语句
  • 问题是:是否有办法强制创建准备好的语句,而不是从语句缓存中重用现有语句?

    如果不是的话,还有什么更好的方法来处理这种情况吗

    • 为没有语句/连接池的批创建单独的数据源
    • 从数据库中删除约束;插入顺序将不再重要
    • 强制顺序处理

    编辑:尝试澄清问题

    假设有线程T1和T2。 准备好报表S1和S2。 设B1和B2批次

    每次使用S1时,都会将其添加到B1中。每次使用S2时,都会将其添加到B2中。 提交时,每个外键约束必须在S2之前提交S1

    问题发生在

    • T1愉快地处理传输
    • T2无辜地处理传输
    • T1使用语句S1将s1a添加到包含s1a的批次B1中
    • T1使用语句S2将s2a添加到包含s2a的批次B2中
    • T1决定是时候提交了
    • T1提交包含s1a的批次B1
    • T2使用S1将s1b添加到含有s1b的批次B1中
    • T2使用S2将s2b添加到包含s2a、s2b的批次B2中
    • T1提交包含s2a、s2b的批次B1
    • 数据库显示“否”,因为s2b在s1b之前提交,这在外键中是禁止的

    这可以通过手动同步避免,也可以在答案中指出,但是我仍然必须单独跟踪每个批的大小,而不是将逻辑本地应用于每个线程

    您是否试图从一个连接实例中使用多个语句?依我看,对于您描述的行为,建议使用连接池。另一种方法是手动同步

    解决方案是特定于供应商的

    如果您的代码在servlet下运行,那么您可以通过在webapp中配置数据源来解决问题。我使用Tomcat下的Oracle驱动程序实现了这一点,但我相信其他应用程序服务器也有类似的方法来配置连接池

    如果代码是独立的,则必须使用特定于供应商的API。由于您将Oracle作为生产数据库,下面是Oracle JDBC驱动程序的一个快速示例:

    import oracle.jdbc.OracleConnection;
    
    ...
    
    public static void disableStatementCaching(java.sql.Connection conn)
            throws SQLException {
        ((OracleConnection)conn).setImplicitCachingEnabled(false);
    }
    
    ...
    

    有关更多信息,请参阅Oracle 10.2的《我当前的解决方案是停止担忧,开始热爱共享批处理》。我将处理算法分为两个阶段

  • 解析一组N条记录并以中间格式保存它们
  • 将锁授予当前线程时,将N个记录集作为一个批持久化
  • 这允许对并发和批处理顺序进行解析。我只需要找到一个最佳点来最小化线程之间的等待时间

    对最佳点的追求可能会导致实现某种两阶段锁定方案,即让每个线程随心所欲,在提交时,确保所有线程在实际批处理执行之前已完成其当前记录


    在后一种解决方案中,可能需要为每个PreparedStatement同步参数设置,尽管我还没有测试这是否会导致任何问题。应该是这样。

    谢谢你的回答。每个线程有一个连接。每个连接都有多个语句,每个单独的SQL语句都有一个PreparedStatement实例。每个语句都包含一个批处理。问题在于,由于语句缓存,每个线程没有唯一的语句集,这会导致批处理出现问题。连接池和语句缓存在这里并没有真正的帮助,因为连接和语句准备事件很少。仍在试图理解这个问题-语句的执行顺序是问题吗?我编辑了这个问题(希望)对场景进行了一些澄清。执行命令导致崩溃,是的。另一方面,共享语句和批处理使得无法信任本地状态。在我看来,这在我的场景中导致了可避免/非有益的并发性,即管理与实际工作线程分离的批。啊。不据我所知,有一种机制可以识别哪些线程可以执行哪些语句需要手动提供。)+:很抱歉,我帮不了你什么忙。你必须使用特定于供应商的方法来完成你需要的工作。您正在与哪些RDBMS合作?啊。那真的不是我想听的。目前,测试系统在ApacheDerby上运行。生产数据库将是Oracle 10g或R。我将对这两个答案进行投票,因为它们帮助我思考了我的问题。我会在测试后提供我选择的解决方案。谢谢你的回答。我肯定会看看特定于供应商的API,尽管我对使用它们有点怀疑。应用程序不是作为servlet运行的。它以web服务的形式发布