|
|
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
БД - Oracle, создан сиквенс и привязан аннотацией к объекту. При создании нового java-объекта поле id изначально равно нулю. Когда объект сохраняется через save(obj) метод отрабатывает успешно и генерируется id отличный от нуля, хотя одно из полей в таблице (назовем его условно field) имеет уникальный индекс. Затем происходит выход из транзакции (из метода, помеченного аннотацией @Transactional). В этот момент выбрасывается исключение нарушения ограничения уникальности field, транзакция откатывается. Сгенерированный id остается в java-объекте, что неприятно, приходится "вручную" его обнулять. Вопрос. Почему исключение не возникло на самом save(obj)? То есть хибер закэшировал вставку?! Ведь если зайти в pl/sql developer и вручную провести подобную операцию, то исключение появится сразу, а не при попытке зафиксировать транзакцию. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 15:29 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaПри создании нового java-объекта поле id изначально равно нулю. Почему не null? myauchaСгенерированный id остается в java-объекте, что неприятно, приходится "вручную" его обнулять. А вот это интересный факт. myauchaВопрос. Почему исключение не возникло на самом save(obj)? Потому что Session aka EntityManager aka Unit of Work ещё называется кешем первого уровня. Это такая оптимизация, чтобы на каждый пук не генерировать SQL запрос. Для особо торопливых есть метод flush() myauchaТо есть хибер закэшировал вставку?! Конечно. myauchaВедь если зайти в pl/sql developer и вручную провести подобную операцию, то исключение появится сразу, а не при попытке зафиксировать транзакцию. Ведь ORM и PL/SQL это не одно и то же? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 15:34 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, По поводу отката id вот тут хорошо описано http://stackoverflow.com/questions/20636144/entity-state-and-entity-id-value-in-jpa-hibernate-after-rollback JPA требует такого поведения Но хибер позволяет включить опцию hibernate.use_identifier_rollback ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 15:38 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
Пока читаю про состояния объекта попутно задам уточняющие вопросы BlazkowiczmyauchaПри создании нового java-объекта поле id изначально равно нулю. Почему не null?Объявлял id как int, поэтому и ноль. Есть какие-то предубеждения против использования простых типов в качестве идентификаторов?! BlazkowiczПо поводу отката id вот тут хорошо описано http://stackoverflow.com/questions/20636144/entity-state-and-entity-id-value-in-jpa-hibernate-after-rollback JPA требует такого поведения Но хибер позволяет включить опцию hibernate.use_identifier_rollbackОпция use_identifier_rollback не помогла. Добавлял ее, как в таком варианте - hibernate.use_identifier_rollback, так и без префикса - use_identifier_rollback. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 16:58 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaЕсть какие-то предубеждения против использования простых типов в качестве идентификаторов?! Конечно. БД разрешает вам хранить 0 в колонке первичного ключа. А вот null не разрешит. myauchaв таком варианте - hibernate.use_identifier_rollback, так и без префикса - use_identifier_rollback. Тут я ничего не могу сказать. Надо посмотреть как он используется в исходнике. И куда вы его вообще пихали. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 17:14 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
BlazkowiczmyauchaЕсть какие-то предубеждения против использования простых типов в качестве идентификаторов?! Конечно. БД разрешает вам хранить 0 в колонке первичного ключа. А вот null не разрешит.Пока не убедили. Если приложение выполняет проверку на id == 0 и отправляет объект в зависимости от результата либо на save(obj), либо на update(obj), то риска вроде бы нет?! myauchaв таком варианте - hibernate.use_identifier_rollback, так и без префикса - use_identifier_rollback. Тут я ничего не могу сказать. Надо посмотреть как он используется в исходнике. И куда вы его вообще пихали.[/quot]В статье (да и в документации к настройке это прописано) высказывались предположения о том, что эта настройка работает только для delete. Код: xml 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Вы-то сами как поступаете в проектах с идентификаторами объектов, когда выполняется Вставка и нарушаются ограничения, приводящие к откату? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 17:28 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaто риска вроде бы нет?! Assumption is the mother of all fuck ups. 1) Целостность данных БД нужно обеспечивать средствами БД, а не ORM. 2) Сторонние библиотеки (например Spring Data) не в курсе деталей вашего Hibernate маппинга и опираются на общие практики, такие как проверку id на null. 3) В случае присвоения кем-то значения 0 по ошибке (генератор сломался или ещё какой лисопед самоуправством занялся) вы не сможете отличить его от значения 0 по-умолчанию. 4) Некоторые бд имеют по-умолчанию инкремент от 0. Что может выйти боком, когда вдруг понадобится портировать с Oracle. Остаётся вопрос. Почему бы сразу не убрать грабли? myauchaВы-то сами как поступаете в проектах с идентификаторами объектов, когда выполняется Вставка и нарушаются ограничения, приводящие к откату? Обычно, я про этот объект забываю. Он невалидный. Зачем мне его состояние? Нужно сформировать новый. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 17:41 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaВы-то сами как поступаете в проектах с идентификаторами объектов, когда выполняется Вставка и нарушаются ограничения, приводящие к откату?Обычно, я про этот объект забываю. Он невалидный. Зачем мне его состояние? Нужно сформировать новый.[/quot]Вколачивал пользователь данные в форму, они пришли в контроллер в виде объекта, объект семантически верный, пытаемся его сохранить, но ограничения в БД не позволили это сделать. Логично передать объект пользователю обратно на доработку. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 18:04 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaВколачивал пользователь данные в форму, они пришли в контроллер в виде объекта, объект семантически верный, пытаемся его сохранить, но ограничения в БД не позволили это сделать. Логично передать объект пользователю обратно на доработку. Во-первых, объекты на UI и в ORM совпадают только в простейших случаях. При большой модели предметной области оказывается очевидным что объекты на UI нужны совсем не такие как в ORM. Во-вторых почему мы в UI потеряли данные, если мы их ещё не сохранили? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 18:14 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, 1.Руками обнулять. 2.Первой же строчкой в сервисе делать копию того, что пришло. 3.Dto и им подобное. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 18:50 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
авторПри большой модели предметной области оказывается очевидным что объекты на UI нужны совсем не такие как в ORM. Вопрос нахрена тогда вообще нужен ORM? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 18:52 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, Значит на sql.ru дураки. Т.к. в форуме если объект не прошел, то он потерян. Хотя написать за свой счет можно что угодно. Заказчик только рад будет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 19:02 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
BlazkowiczВо-первых, объекты на UI и в ORM совпадают только в простейших случаях. При большой модели предметной области оказывается очевидным что объекты на UI нужны совсем не такие как в ORM. Во-вторых почему мы в UI потеряли данные, если мы их ещё не сохранили?В общем понятно. В простом случае (когда объект ввода является объектом сохранения) тот объект, который приходит в контроллер надо копировать и сохранять в базу уже копию. Если транзакция завершается откатом, то копию забываем и передаем пользователю для повторного редактирования оригинал. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 19:05 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, Разве при райзе у вас объект куда то пропал? 1. Правило в веб - не допускать райзе. Откуда оно? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 19:09 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
no56892Вопрос нахрена тогда вообще нужен ORM? Ну, если у вас кроме UI и БД других слоёв нет, то в вашей архитектуре, вероятно не нужен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 20:13 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaВ общем понятно. В простом случае (когда объект ввода является объектом сохранения) тот объект, который приходит в контроллер надо копировать и сохранять в базу уже копию. Если транзакция завершается откатом, то копию забываем и передаем пользователю для повторного редактирования оригинал. Обратите ещё внимание на такую фичу hibernate как dirty check. Описанный вами вариант не единственный. Например можно контроллер научить заполнять уже загруженный объект. А не использовать тот, который он создал. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.08.2016, 20:16 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
Еще один вопрос. Поскольку он связан с существующим, то не буду создавать отдельную тему. Если происходит сохранение объекта в методе контроллера через вызов service.save(obj). Метод используется для создания нового объекта или изменения существующего. Известно, что при сохранении могут возникнуть две ошибки, которые должны быть обработаны. Первая ошибка ObjAlreadyExists возникает когда объект с указанным именем уже существует в базе, вторая ObjNotFound - объект не найден в базе (например, в результате оптимистичного метода редактирования и последующего сохранения). Естественно возникает желание сделать нечто такое: Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. В самом service.save вызывается dao.save, в нем генерируются исключения, но не ObjAlreadyExists или ObjNotFound, а другие унаследованные от DataAccessException или от RuntimeException. Причем, реализация dao может быть выполнена для jdbc, для hibernate или для чего-то еще. В каждой реализации исключения будут разные (некоторые могут и совпадать). Есть желание трансформировать их в ObjAlreadyExists и ObjNotFound. В документации Spring указано, что потомки DataAccessException - это преобразованные (например, из jdbc или hibernate исключений) runtime-исключения, и что Spring рекомендует использовать именно их вместо нудных описаний throws в методах. Предположим, их доводы убедительны плюс не хочется засорять код dao-реализаций конструкциями try/catch и генерированием соответствующих ObjAlreadyExists и ObjNotFound-исключений. Поэтому объявляю ObjAlreadyExists и ObjNotFound наследниками runtime-исключений и пытаюсь их преобразовать... Вопрос где лучше сделать такое преобразование?! Если сделать отдельный метод в контроллере, обозначив его аннотацией @ExceptionHandler, то после преобразования уже, насколько я понимаю, не получится вернуться в try/catch obj = service.save(obj) и продолжить оперировать объектами obj или bindingResult. То есть, существует ли способ перехватить исключение, выполнить преобразование и продолжить подниматься по цепочке вызовов. Насколько я понял, разные варианты реализации обработки - @ControllerAdvice или интерфейс HandlerExceptionResolver - это все обработка упущенных (необработанных) исключений. А нужен некий interceptor. Может вообще надо делать по-старинке (по крайней мере для данного примера) - в dao перехватывать исключения и генерировать ObjAlreadyExists и ObjNotFound, унаследованные от обычного Exception. И протянуть (посредством throws-описания в заголовке метода) их через dao.save и service.save, обязав к тому же пользователя предусмотреть обработку try/catch?! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.09.2016, 18:02 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaЕще один вопрос. Поскольку он связан с существующим, то не буду создавать отдельную тему. В подфоруме Java все вопросы связаны одной технологией. Ваш новый вопрос к первоначальному ведь не относится совершенно. myauchaПервая ошибка ObjAlreadyExists возникает когда объект с указанным именем уже существует в базе У объектов нет имён. И кстати, в случае ORM говорят о сущностях (entity), потому как два объекта могут быть одной сущностью, например. myauchaвторая ObjNotFound - объект не найден в базе (например, в результате оптимистичного метода редактирования и последующего сохранения). Вот этого я вообще не понял. Как NotFound связан с оптимистичной блокировкой? myauchaВ самом service.save вызывается dao.save, в нем генерируются исключения, но не ObjAlreadyExists или ObjNotFound DAO для ORM почти бесполезны. Обычно они вырождаются в Repository. myaucha, а другие унаследованные от DataAccessException или от RuntimeException. Если вам это критично, то нужно для каждой реализации написать обработчик и конвертор исключений. http://docs.spring.io/autorepo/docs/spring/4.2.x/spring-framework-reference/html/dao.html myauchaПричем, реализация dao может быть выполнена для jdbc, для hibernate или для чего-то еще. Я надеюсь вы не используете одну и ту же базу для JDBC и ORM? myauchaВ документации Spring указано, что потомки DataAccessException - это преобразованные (например, из jdbc или hibernate исключений) runtime-исключения, и что Spring рекомендует использовать именно их вместо нудных описаний throws в методах. Зачем вы всё в кучу мешаете? DataAccessException это одно. Runtime vs Checked Exception это отдельная тема. myauchaВопрос где лучше сделать такое преобразование?! Очевидно, что в DAO. myauchaЕсли сделать отдельный метод в контроллере, обозначив его аннотацией @ExceptionHandler, то после преобразования уже, насколько я понимаю, не получится вернуться в try/catch obj = service.save(obj) и продолжить оперировать объектами obj или bindingResult. То есть, существует ли способ перехватить исключение, выполнить преобразование и продолжить подниматься по цепочке вызовов. Насколько я понял, разные варианты реализации обработки - @ControllerAdvice или интерфейс HandlerExceptionResolver - это все обработка упущенных (необработанных) исключений. А нужен некий interceptor. Ну, логично что это можно сделать через AOP. Но только не на уровне MVC, когда уже поздно обрабатывать ошибку обращения к данным. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.09.2016, 18:28 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, Где ты взял эти исключения? У тебя весь роман текста построен на этих двух именах. Может SaveOrUpdate (объект ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 01.09.2016, 19:00 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
В итоге получилось следующее Исключения Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Контроллер Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. Сервис Код: java 1. 2. 3. 4. 5. 6. 7. 8. DAO (JDBC) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. DAO (Hibernate) Код: java 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Особенности: Поскольку исключения UserAlreadyExists и UserNotFound рантаймовские, то при написании в контроллере userService.save не будет требования их обработки - это минус. Зато не надо тянуть их через слои и прописывать атрибут rollbackFor для @Transactional, чтобы откатывалась транзакция. Странности: В DAO для jdbc перехватывается ошибка spring-а DuplicateKeyException, то есть уже после преобразования. В DAO же для hibernate перехватываются хибернетовские исключения ConstraintViolationException и StaleStateException. Если выйти из хибернетовского save, то ошибка останется по-прежнему ConstraintViolationException. Если выйти из сервисного save, то исключение преобразуется в spring-овое. Если теперь прописать в настройках Код: xml 1. , то В DAO для hibernate по-прежнему перехватываются хибернетовские исключения, на выходе они преобразуются в spring-овые, при выходе из транзакции как и раньше - spring-овые. Сейчас, пока писал, понял почему для JDBC сразу получаю spring-овое - потому что через jdbcTemplate работаю. Так что все понятно. Ну и flush пришлось все-таки написать, потому что иначе ошибку можно будет отловить только на выходе из транзакции (то есть в контролере), а тогда уже поздно - выходить из сервиса ошибка должна уже преобразованной. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:19 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myauchaUserAlreadyExists и UserNotFound где взял эти исключения? Их не будет при сохранении объекта хибером. 19618727 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:28 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, вот это DuplicateKeyException - с чего вдруг у тебя появится? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:32 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
myaucha, У тебя какая-то фигня с настройкой Spring + hibernate походу. DuplicateKeyException это если только делать persist с уже проставленным id - то возможно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:49 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
no56892myaucha, У тебя какая-то фигня с настройкой Spring + hibernate походу. DuplicateKeyException это если только делать persist с уже проставленным id - то возможно. +1 Что-то он неделю борется как Дон кихот с этой проблемой. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:55 |
|
||
|
Hibernate - cохранение объекта
|
|||
|---|---|---|---|
|
#18+
В хибере (ОРМ) всё просто: - мы знаем какой (новый или существующий) мы правим и указываем хиберу - хибер сам знает что делать чтобы исключений не было - если СПЕЦИАЛЬНО указать ему что не надо затирать изменения соседом, то будет исключение всего одно по оптимистической блокировке. Всё. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 02.09.2016, 11:58 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=39301435&tid=2123753]: |
0ms |
get settings: |
6ms |
get forum list: |
8ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
146ms |
get topic data: |
7ms |
get forum data: |
2ms |
get page messages: |
42ms |
get tp. blocked users: |
1ms |
| others: | 241ms |
| total: | 457ms |

| 0 / 0 |
