Java

EclipseLinkをつかってDBプログラミングをする part1

始めに

業務で必要になりそうなので、EclipseLinkを使ってDBプログラミングをしてみた

サンプルプログラム

1の連番をDBにインサートするプログラムを書いてみた

InsertLogic.java
package logic;

import java.util.Date;
import java.util.stream.Stream;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import entiry.SequeceNum;


public class InsertLogic {
    public static void main(String args[]){
        new InsertLogic().doLogic();
    }

    public void doLogic(){
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myUnitInPersistenceXML");
        EntityManager em = factory.createEntityManager();
        long start =System.currentTimeMillis();
        System.out.println("insert start");
        em.getTransaction().begin();

        Stream.iterate(1l, s->s+1)
        .limit(1000000000000l)
        .map(i->createSequeceNum(i))
        .forEach(o->doInsert(em,o));
        System.out.println("insert End");
        long ends =System.currentTimeMillis();
        System.out.println(String.format("かかった時間  %d", (ends - start)));

    }

    private static SequeceNum createSequeceNum(long i){
        SequeceNum myEntity = new SequeceNum();
        myEntity.setId(i);
        return myEntity;
    }
    private static void doInsert(EntityManager em,SequeceNum entity){
        em.persist(entity);
        if(entity.getId()%100000 == 0){
            em.getTransaction().commit();
            em.getTransaction().begin();
        }
    }
}
SequeceNum.java
package entiry;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class SequeceNum {
    @Id
    private long id;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

このまま実行すると、以下のエラーがでる

[EL Info]: 2017-12-03 21:56:37.505--ServerSession(336400944)--EclipseLink, version: Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5
[EL Info]: connection: 2017-12-03 21:56:38.156--ServerSession(336400944)--file:/C:/Users/takayoshi/workspace/Pazzle/bin/_myUnitInPersistenceXML login successful
insert start
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.createObjectChangeSet(ObjectBuilder.java:2872)
    at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSetThroughComparison(DeferredChangeDetectionPolicy.java:155)
    at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.createObjectChangeSet(DeferredChangeDetectionPolicy.java:146)
    at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:91)
    at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChangesForExistingObject(DeferredChangeDetectionPolicy.java:56)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:664)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1516)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
    at logic.InsertLogic.doInsert(InsertLogic.java:43)
    at logic.InsertLogic.lambda$2(InsertLogic.java:28)
    at logic.InsertLogic$$Lambda$6/2137034273.accept(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
    at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.util.stream.SliceOps$1$1.accept(Unknown Source)
    at java.util.Spliterators$IteratorSpliterator.tryAdvance(Unknown Source)
    at java.util.stream.ReferencePipeline.forEachWithCancel(Unknown Source)
    at java.util.stream.AbstractPipeline.copyIntoWithCancel(Unknown Source)
    at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
    at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.util.stream.ReferencePipeline.forEach(Unknown Source)
    at logic.InsertLogic.doLogic(InsertLogic.java:28)
    at logic.InsertLogic.main(InsertLogic.java:15)
[EL Info]: connection: 2017-12-03 22:23:39.469--ServerSession(336400944)--file:/C:/Users/takayoshi/workspace/Pazzle/bin/_myUnitInPersistenceXML logout successful

どうやら、メモリに実行した結果がキャッシュに残っているらしく、ヒープ領域が枯渇したようだ
ちなみに、ヒープが枯渇した時にDBにインサートした行数は以下の通り

  COUNT(*)
----------
   2400001

どうやら、何の工夫もなくInsert文を実行するとシンプルなデータ構造でも25万件程度でエラーが発生するらしい
改善案は次のエントリで書いてみる