我正在使用Spring MVC 4,Spring Batch 3,Hibernate 5和Ehcache 2.8。使用Spring Batch,我使用Hibernate以1000块的形式将大量数据从CSV导入数据库。有关其他信息,CSV中的数据指的是其他表,这就是我在实际插入之前有大量数据库查询的原因。
首先,块之间的间隔很小,在10秒之间。逐渐地,在大约100,000件物品之后,物品之间的间隔超过1分钟。我怀疑这是一些缓存问题,因为这是逐渐退化。我目前的hibernate统计信息是
这是我的ehcache.xml配置
<defaultCache
eternal="false"
timeToIdleSeconds="180"
timeToLiveSeconds="240"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="50000"
>
<persistence strategy="localTempSwap" />
</defaultCache>
<cache name="org.hibernate.cache.internal.StandardQueryCache"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="50000"
eternal="false"
timeToIdleSeconds="180"
timeToLiveSeconds="240"
>
<persistence strategy="localTempSwap" />
</cache>
<cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
eternal="false"
maxEntriesLocalHeap="0"
/>
[编辑],这是批处理作业的源代码
@Bean
@StepScope
public static FlatFileItemReader<CsvPayment> paymentReader( @Value( "#{jobParameters[fullPathFileName]}" ) String pathToFile,
@Value( "#{jobParameters[delimeter]}" ) String delimeter,
@Value( "#{jobParameters[skipItems]}" ) Long skipItems,
@Value( "#{jobParameters[limitItems]}" ) Long limitItems )
{
FlatFileItemReader<CsvPayment> reader = new FlatFileItemReader<>();
reader.setResource( new FileSystemResource( pathToFile ) );
reader.setEncoding( GlobalConstants.UTF8 );
reader.setMaxItemCount( limitItems.intValue() );
reader.setLinesToSkip( skipItems.intValue() );
reader.setLineMapper( new CsvPaymentLineMapper( delimeter ) );
return reader;
}
@Bean( "importPayment" )
public Job importPayment( ItemReader<CsvPayment> paymentReader )
{
return jobBuilderFactory.get( "paymentReader" ).incrementer( new RunIdIncrementer() ).flow(
paymentStep1( paymentReader ) ).end().build();
}
@Bean
public Step paymentStep1( ItemReader<CsvPayment> paymentReader )
{
return stepBuilderFactory.get( "paymentStep1" ).<CsvPayment, OccupancyPayment> chunk( CHUNK_SIZE ).reader(
paymentReader ).processor( itemProcessor ).faultTolerant().listener(
new ChunkListenerImpl( logger ) ).writer( itemWriter() ).build();
}
@Bean
public HibernateItemWriter<OccupancyPayment> itemWriter()
{
HibernateItemWriter<OccupancyPayment> itemWriter = new HibernateItemWriter<>();
itemWriter.setSessionFactory( sessionFactory );
itemWriter.setClearSession( true );
return itemWriter;
}
希望有人可以指出我正确的方向。感谢。
答案 0 :(得分:0)
会话缓存正在增长,使您的应用程序变慢并消耗更多内存。
试试这个:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
取自here的示例,我向您确认我们使用相同的解决方案并且效果很好。
解决方案的唯一缺点是有时你可能会从Hibernate获得NonUniqueObjectException
。它是session.clear()
的结果,它使所有Hibernate实例分离。在这种情况下,您肯定需要阅读this并且可能会调用session.refresh(instance)
。