Несмотря ни на что, я не могу пакетировать операторы MySQL INSERT в Hibernate
m в настоящее время сталкивается с хорошо известной и распространенной проблемой пакетной обработки Hibernate.
Мне нужно сохранить партии длиной 5 миллионов строк. Я'Я сначала пытаюсь с гораздо более легкой полезной нагрузкой. Так как мне нужно вставить объекты только 2 типов (сначала все записи типа A, затем все записи типа B, все они указывают на общий тип C)ManyToOne
родитель), я хотел бы получить максимальную выгоду от пакетной вставки JDBC.
Я уже прочитал много документации, но ни одна, которую я пробовал, не сработала.
я знаю что для использования пакетных вставок я не должен использовать генератор сущностей. Поэтому я удалилAUTO_INCREMENT
ID и ям, установив идентификатор с помощью хитрости:SELECT MAX(ID) FROM ENTITIES
и увеличивать каждый раз.я знаю что я должен регулярно промывать сессию. Я'Я опубликую код впереди, но в любом случае я выполняю транзакцию каждые 500 элементов.я знаю что я должен установитьhibernate.jdbc.batch_size
в соответствии с моим заявлениемS, так что я установил его вLocalSessionFactoryBean
(Spring ORM интеграция)я знаю Я должен включить переписывание пакетных операторов в URL-адресе соединения.Вот мои сущности
Общий родительский объект. Это вставляется первым в одной транзакции. Я нене заботится об автоинкрементном столбцеВот, Толькоодин запись за пакетное задание
@Entity
@Table(...)
@SequenceGenerator(...)
public class Deal
{
@Id
@Column(
name = "DEAL_ID",
nullable = false)
@GeneratedValue(
strategy = GenerationType.AUTO)
protected Long id;
................
}
Один из детей (пустьскажем, 2,5 млн записей на партию)
@Entity
@Table(
name = "TA_LOANS")
public class Loan
{
@Id
@Column(
name = "LOAN_ID",
nullable = false)
protected Long id;
@ManyToOne(
optional = false,
targetEntity = Deal.class,
fetch = FetchType.LAZY)
@JoinColumn(
name = "DEAL_ID",
nullable = false)
protected Deal deal;
.............
}
Другие дети типа. Позволять'скажем, другие записи 2.5M
@Entity
@Table(
name = "TA_BONDS")
public class Bond
{
@Id
@Column(
name = "BOND_ID")
@ManyToOne(
fetch = FetchType.LAZY,
optional = false,
targetEntity = Deal.class)
@JoinColumn(
name = "DEAL_ID",
nullable = false,
updatable = false)
protected Deal deal;
}
Упрощенный код, который вставляет записи
long loanIdCounter = loanDao.getMaxId(), bondIdCounter = bondDao.getMaxId(); //Perform SELECT MAX(ID)
Deal deal = null;
List bondList = new ArrayList(COMMIT_BATCH_SIZE); //500 constant value
List loanList = new ArrayList(COMMIT_BATCH_SIZE);
for (String msg: inputStreamReader)
{
log.debug(msg.toString());
if (this is a deal)
{
Deal deal = parseDeal(msg.getMessage());
deal = dealManager.persist(holder.deal); //Called in a separate transaction using Spring annotation @Transaction(REQUIRES_NEW)
}
else if (this is a loan)
{
Loan loan = parseLoan(msg.getMessage());
loan.setId(++loanIdCounter);
loan.setDeal(deal);
loanList.add(loan);
if (loanList.size() == COMMIT_BATCH_SIZE)
{
loanManager.bulkInsert(loanList); //Perform a bulk insert in a single transaction, not annotated but handled manually this time
loanList.clear();
}
}
else if (this is a bond)
{
Bond bond = parseBond(msg.getMessage());
bond.setId(++bondIdCounter);
bond.setDeal(deal);
bondList.add(bond);
if (bondList.size() == COMMIT_BATCH_SIZE) //As above
{
bondManager.bulkInsert(bondList);
bondList.clear();
}
}
}
if (!bondList.isEmpty())
bondManager.bulkInsert(bondList);
if (!loanList.isEmpty())
loanManager.bulkInsert(loanList);
//Flush remaining items, not important
Реализация :bulkInsert
@Override
public void bulkInsert(Collection bonds)
{
// StatelessSession session = sessionFactory.openStatelessSession();
Session session = sessionFactory.openSession();
try
{
Transaction t = session.beginTransaction();
try
{
for (Bond bond : bonds)
// session.persist(bond);
// session.insert(bond);
session.save(bond);
}
catch (RuntimeException ex)
{
t.rollback();
}
finally
{
t.commit();
}
}
finally
{
session.close();
}
}
Как вы можете видеть из комментариев, я пробовал несколько комбинаций с состоянием / без состоянияsession
, Никто не работал.
мойdataSource
этоComboPooledDataSource
со следующим URL
мойSessionFactory
${hibernate.dialect}
${hibernate.showSQL}
500
false
false
org.hibernate.cache.EhCacheProvider
false
false
false
true
true
Даже если мой класс проекта расширяетсяLocalSessionFactoryBean
, Этоне переопределить его методы (только добавляет несколько методов для всего проекта) I '
Я злюсь уже несколько дней. Я прочитал несколько статей, и ни одна из них не помогла мне включить пакетную вставку. Я запускаю весь свой код из тестов JUnit, оснащенных контекстом Spring (так что я могу@Autowire
мои занятия). Все мои попытки дают только много отдельныхINSERT
заявления
Что мне не хватает?