2009-08-25 52 views
1

我正在开发一个应该接收来自数百个业务部门的夜间报告的服务器。报告目前是加密的csv文件。这些报告总共应该每天保存在数据库中以供日后使用,其数量应达到50万到100万条。如何在并发批处理中绕过JDBC语句缓存?

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

因为我试图同时做到这一点,我注意到不同的线程得到了完全相同的PreparedStatements实例。这引起了以下问题

  1. 多个线程添加语句到同一批次当任何线程决定是时候这样做
  2. 提交被调用时数据库没有达到它的
  3. 批次正在执行约束一些线程还没有来得及使用某些语句

的问题是:是那里是要创建一种强制一份声明而不是重用现有从语句缓存?

如果不是有没有更好的方式来处理比

  • 创建不具有语句/连接池
  • 从数据库中取消约束批次单独的数据源的情况;插入顺序也没有什么关系了
  • 迫使顺序处理

编辑:试图澄清这一问题

要有线程T1和T2。 让我们准备好陈述S1和S2。 让批次B1和B2。

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

  • T1处理传输兴高采烈
  • T2处理传输发生

    问题无辜

  • T1使用语句S1添加S1A到含有批量B1 S1A
  • T1使用语句S2添加S2A批量B2包含s2a
  • T1决定是时候提交
  • T1提交batch B1 contai宁S1A
  • T2使用S1添加S1b到含有批量B1 S1B
  • T2使用S2添加含有S2A S2B到批次B2,S2B
  • T1提交批处理B1 containting S2A,S2B
  • 数据库说 '否'因为s2b是在外键禁止的s1b之前提交的。

这可以避免与手动同步以及指出的答案,但然后我仍然需要分别跟踪每个批次的大小,而不是应用每个线程的本地逻辑。

+0

您必须使用供应商特定的方法来执行您所需的操作。你在使用哪种RDBMS? – Juris 2009-08-25 11:41:01

+0

Aww。这真的不是我想听到的。目前该测试系统在Apache Derby上运行。生产数据库将是Oracle 10g或R – 2009-08-25 11:54:47

+0

我会给予两个答案upvote,因为他们帮助我考虑了我的问题。我会提供我在设法测试时选择的解决方案。 – 2009-08-26 04:24:11

回答

0

我目前的解决方案是停止担忧,并开始爱上共享批次。我已在处理算法分为两个阶段

  1. 解析一组N个记录,并将其设定的N个记录保存在intermidiate格式
  2. 坚持为批处理时,锁被授予当前线程

这允许解析并发和按顺序分批。我只需要找到一个最佳位置来减少线程之间的等待时间。

对甜蜜点的追求可能会导致实现某种双相锁定方案,即让每个线程按照自己的意愿执行,并在提交时确保所有线程在实际批处理执行之前完成其当前记录。

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

1

您是否试图在单个连接实例中使用多个语句?国际海事组织(IMO)建议为您描述的行为建立连接池。另一种方法是手动同步。

+0

谢谢你的回答。 每个线程都有一个连接。每个连接都有多个语句,每个单独的SQL语句都有一个PreparedStatement实例。每个语句都包含一个批次。 问题是,由于语句缓存,每个线程没有一个唯一的语句集,导致批处理问题。 连接池和语句缓存在这里并没有什么帮助,因为连接和语句准备事件很少。 – 2009-08-25 10:06:12

+0

仍然试图理解这个问题 - 这个问题的执行顺序是什么? – Everyone 2009-08-25 10:59:06

+0

我编辑了问题(希望),以方案的一些澄清。执行顺序导致崩溃,是的。另一方面,共同的声明和批次使得不可能信任当地的国家。在我看来,这在我的方案中引起了可避免/非有利的并发,即将批量与实际工作线程分开管理。 – 2009-08-25 11:29:50

1

该解决方案是供应商特定的。

如果您的代码在servlet下运行,那么您可以通过在Web应用程序中配置数据源来解决您的问题。我已经使用Tomcat下的Oracle驱动程序完成了这项工作,但我确信其他应用程序服务器具有类似的配置连接池的方法。

如果您的代码是独立的,那么您必须使用供应商特定的API。正如你将针对Oracle用作生产数据库,这里是为Oracle JDBC驱动程序一个简单的例子:

import oracle.jdbc.OracleConnection; 

... 

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

... 

欲了解更多信息,请参阅JDBC dev guide甲骨文10.2

+0

谢谢你的回答。即使我对使用它们持怀疑态度,我也一定会看看供应商特定的API。 该应用程序不作为servlet运行。它作为EJB3 @WebService -annotation定义的Web服务发布。但是,使用应用程序服务器定义的数据源并对其进行配置是完全可能的。它只需要适当的文档,这可能会导致未来开发人员决定通过启用语句缓存来优化性能。 – 2009-08-26 04:21:13