Я пытаюсь сделать каскадное сохранение на большом объектном графе, используя JPA. Например (мой граф объектов немного больше, но достаточно близко):
@Entity
@Table(name="a")
public class A {
private long id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "a")
private Collection<B> bs;
}
@Entity
@Table(name="b")
public class B {
private long id;
@ManyToOne
private A a;
}
Так что я пытаюсь сохранить A, у которого есть коллекция из 100+ B. Код просто
em.persist(a);
Проблема в том, что МЕДЛЕННО. Мое сохранение занимает около 1300 мс. Я посмотрел на генерируемый SQL, и он ужасно неэффективен. Примерно так:
select a_seq.nextval from dual;
select b_seq.nextval from dual;
select b_seq.nextval from dual;
select b_seq.nextval from dual;
...
insert into a (id) values (1);
insert into b (id, fk) values (1, 1);
insert into b (id, fk) values (2, 1);
insert into b (id, fk) values (3, 1);
...
В настоящее время использую toplink в качестве поставщика сохраняемости, но я также попробовал eclipselink и hibernate. Бэкэнд это оракул 11г. Проблема действительно в том, как соединить sql. Каждая из этих операций выполняется дискретно, а не навалом, поэтому, если между моим appserver и сервером БД задержка в сети составляет даже 5 мс, выполнение 200 дискретных операций добавляет 1 секунду. Я попытался увеличить размер размещения моих последовательностей, но это только немного помогает. Я также пробовал использовать JDBC в качестве пакетного оператора:
for...{
statement = connection.prepareStatement(sql);
statement.addBatch();
}
statement.executeBatch();
Для моей модели данных требуется около 33 мсек, как для прямой JDBC-партии. Сама Oracle берет 5 мс для 100+ вставок.
Есть ли способ заставить JPA (я застрял с 1.0 прямо сейчас ...) работать быстрее, не углубляясь в специфические вещи поставщика, такие как массовая вставка в спящий режим?
Спасибо!