Использую JPA RI (TopLink essentials) в stand-alone J2SE приложении. Программное управление транзакциями и явное создание EntityManager.
1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать
2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
Здравствуйте, Trean, Вы писали:
T>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать
Ограничивать единоразовое кол-во записей, т.е. реализовать paging... http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setFirstResult(int) http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setMaxResults(int)
T>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
Flush — выполняет накопленные (pending) изменения в виде sql запросов (т.е. например myEntity.setSomeValue(1); em.save(myEntity); не приводит к немедленному update myentity set ... ).
Commit — это явный коммит транзакции... Если данные попадают в бд, возможно не выключeн autocommit
В toplink разве нельзя включить режим логгирования состояний соединений чтобы видеть когда оно коммит делает?
Здравствуйте, Trean, Вы писали:
T>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать
не важно, что именно более критично — скорость или память, но наиболее практичным подходом для массовой загрузки данных является использование СУБД-зависимых тулов (типа sqlldr для oracle). любая своя поделка чревата багами и будет уступать как в гибкости, так и по расходу ресурсов (memory + cpu)
дальнейшая обработка загруженных данных более эффективно производится в хранимках, чтобы не таскать туда-сюда данные из СУБД в Java и наоборот
T>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
Мне не на чтение, а на запись. Когда я вызываю persist для объектов, они все хранятся в контексте до самого коммита. По спеке вроде flushmode.AUTO по дефолту включен, но OOE вылетает все равно. Мне бы flush + clear бы помогло думаю, но для этого надо разобраться со второй проблемой.
T>>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе. A>Flush — выполняет накопленные (pending) изменения в виде sql запросов (т.е. например myEntity.setSomeValue(1); em.save(myEntity); не приводит к немедленному update myentity set ... ). A>Commit — это явный коммит транзакции... Если данные попадают в бд, возможно не выключeн autocommit A>В toplink разве нельзя включить режим логгирования состояний соединений чтобы видеть когда оно коммит делает?
Скачал последний билд с сорсами, включу логгинг посмотрю что происходит, отпишу потом.
Здравствуйте, aka50, Вы писали:
A>Здравствуйте, Trean, Вы писали:
T>>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать A>Ограничивать единоразовое кол-во записей, т.е. реализовать paging... A>http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setFirstResult(int) A>http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#setMaxResults(int)
А как размер всего результата можно узнать?
Тупо смотреть размер результирующего списка или слать запрос типа select count(*)? Оба варианта какие то некрасивые — первый неоптимальный, а второй иногда неудобный в плане реализации...
Здравствуйте, C0s, Вы писали:
C0s>Здравствуйте, Trean, Вы писали:
T>>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать
C0s>не важно, что именно более критично — скорость или память, но наиболее практичным подходом для массовой загрузки данных является использование СУБД-зависимых тулов (типа sqlldr для oracle). любая своя поделка чревата багами и будет уступать как в гибкости, так и по расходу ресурсов (memory + cpu)
Согласен, но я прототип приложения пока пишу для верификации объектной модели, и на данном этапе хотел бы абстрагироваться от конкретного вендора будь-то оракл или mysql. Потом уже можно будет что-то оптимизировать. Мне сейчас важнее разобраться как правильно работать с JPA и в частности с вышеуказанной проблемой.
C0s>дальнейшая обработка загруженных данных более эффективно производится в хранимках, чтобы не таскать туда-сюда данные из СУБД в Java и наоборот
Смотря что понимать под обработкой загруженных данных. Я бы не хотел бизнес логику реализовывать на хранимках, кроме случаев, когда это действительно единственный выход.
T>>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
C0s>autocommit забыл выключить?
А как его выключить-то, я ж не работаю с соединениями напрямую? Логично чтобы этим занимался EntityManager сам при вызове EntityManager.getTransaction().
Здравствуйте, Дмитрий В, Вы писали:
ДВ>А как размер всего результата можно узнать? ДВ>Тупо смотреть размер результирующего списка или слать запрос типа select count(*)? Оба варианта какие то некрасивые — первый неоптимальный, а второй иногда неудобный в плане реализации...
Здравствуйте, Trean, Вы писали:
T>Использую JPA RI (TopLink essentials) в stand-alone J2SE приложении. Программное управление транзакциями и явное создание EntityManager.
T>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать T>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
T>З.Ы. С хибернейтом и jdo до этого не работал.
T>Спасибо
Всем спасибо за советы, виновата моя невнимательность — совершенно упустил из виду что MYISAM не поддерживает транзакции. При переходе на INNODB все работает как часы. Остался вопрос только, как указать в peristense.xml для mysql провайдера свойство, чтобы генерились INNODB таблицы.
Здравствуйте, Trean, Вы писали:
T>Здравствуйте, Trean, Вы писали:
T>>Использую JPA RI (TopLink essentials) в stand-alone J2SE приложении. Программное управление транзакциями и явное создание EntityManager.
T>>1. Как в JPA внести большое (скажем 100k) записей в рамках одной транзакции? Сразу скажу: скорость выполнения операции менее важна, чем объем требуемой памяти (вылетает out of memory error — так как все объекты лежат в контексте). Plain-JDBC не предлагать T>>2. Чем вызов метода flush отличается от commit и можно ли откатить транзакцию после вызова flush. У меня при явном вызове вызове rollback данные остаются в базе.
T>>З.Ы. С хибернейтом и jdo до этого не работал.
T>>Спасибо
T>Всем спасибо за советы, виновата моя невнимательность — совершенно упустил из виду что MYISAM не поддерживает транзакции. При переходе на INNODB все работает как часы. Остался вопрос только, как указать в peristense.xml для mysql провайдера свойство, чтобы генерились INNODB таблицы.
Что все работает, это я поторопился сказать, память все равно заканчивалась. Вот можно сказать официальный ответ получил от разработчиков топ-линковской имплементации JPA после того как порылся в сорсах (там в одном месте не очищается hashtable при clear):
"Caching provides a benefit for a vast majority of users but TopLinks caching mechanism requires tracking of the objects in the current transaction to ensure the cache contains current information. There is currently no JPA defined mechanism to notify the Persistence Provider that a transaction will contain only inserts so TopLink has to assume that the transaction will include other forms of data modifications. The only way to prevent the out of memory is to keep the transactions moderate in size."
(c) Gordon Yorke
Так что будьте внимательны в любом случае Остался, правда, вопрос почему они создают отдельный запрос, судя по логу, для каждой записи в базу вместо batchUpdate. Спрошу в другой раз. Надо посмотреть Hibernate реализацию к JPA.