Comments 64
Потому что на конструктив нужно очень много времени и кода, а если я буду посреди рабочего дня катать простыни на хабр — меня уволят :(
Так вот. Здесь написан лютый ад. Который приведет к куче проблем. Мы тут поревьюили этот туториал, и никак не оправимся от шока, кровь стынет в жилах.
В 2016 году всё это делается немного по-другому, и поэтому, цитирую, «Результаты ошибок могут заставить понервничать. » — почти не происходит.
Такие дела.
Возможно, стоит написать книжку по Hibernate на русском языке, где такие вопросы будут подробно рассмотрены?
1. Кто знает как нужно, и знает как нужно именно правильно (позитивный опыт) — ему и так хорошо.
2. Кто хочет узнать, пользуется (и в принципе и должен начинать пользоваться) тем, что наработано до него.
3. Естественно, какой материал (подход) изложен, на том и «летают»…
Читать мануалы — это отлично, и правильно… но кто знает водителя, который научился ездить, читая руководство по эксплуатации автомобиля. Если вы хотите поделиться опытом, все ждем… ) Подпишусь на ваши статьи первым.
по вопросу передачи знаний — обычно оно передается от учителя к ученику в джава-компаниях. Код, в котором сто сорок раз скопипастана кривая обертка запуска функции в транзакции, просто не пройдет первое же ревью. Там достаточно всего несколько дней, чтобы набить шишки, поэтому такие вещи становятся самоочевидными и ни в какие мануалы не попадают
1) выкосить все маппинги в XML, так никто не делает.
(без веских оснований, а у совсем новичка этих веских оснований быть не может)
да, придется попотеть. Да, нужно.
2) заметка для обучения: чтобы не читать весь талмуд документации, можно прочитать всего одну документацию: https://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
Каждый пункт из этой документации нужно попробовать хотя бы по 1 разу.
3) никогда не копипастайте DAO
вот первое что нашлось в гугле (эта статья написана, когда я был еще маленьким: https://www.ibm.com/developerworks/ru/library/j-genericdao/)
4) и вообще ничего не копипастайте. Особенно вот это открытие сессии сто раз.
3) следующим вашим желанием будет написать свое велосипедное DAO. Если вы фигачите в продакшен, от этого желания нужно избавиться и взять что-нибудь готовое. Например, Hibernate Generic Dao (у него кажется загнулся сайт, так что придется вам самим нагуглить документацию. В Maven Central он лежит, а исходник вот: https://github.com/based2/hibernate-generic-dao)
5) сейчас все пользуются Maven'ом, поэтому неплохо было бы увидеть помку для вашего проекта. Со всеми зависимостями.
6) запускать Hibernate в main функции — это весьма странно даже для туториала. Там есть ряд проблем, связанных с тем, что разрабы фреймворков рассчитывают, что вы будете запускать приложение в контейнере или апликейшен-сервере.
Вместо main(), возьмите какой-нибудь Tomcat или Wildfly.
7) так как у вас уже появился контейнер, сразу же добавьте туда Spring и выкосите ручную работу с транзакциями. Вам нужна аннотация @Transactional.
8) а если уж так прикипело душой к интерфейсу командной строки, то хотя бы уберите этот жуткий свич и впилите Apache Commons CLI. Тогда можно будет легко модифицировать ваш пример для того, чтобы методы у энтити принимали параметры, а не просто 12345. Код консольного гуя тоже нужно причесать и отрефакторить: например, ввод строк пользователя лучше вынести в отдельные методы, а не фигачить readline прямо посреди бизнес-логики, а то получилась каша
9) сообщения лога никогда не выводятся через println или упаси б-же printStackTrace. Используйте логгер из slf4j.
10) Set, Map и прочие вещи, котоыре основываются на hashcode — это очень плохо для Hibernate. Вообще в джаве с equals всё очень плохо. По возможности, не пользуйтесь этим. Если можно без хлопот использовать листы — используйте листы.
11) Там по тексту где-то были итераторы — по возможности, не пользуйтесь ими, нужно использовать упрощенную запись for, либо Stream API
12) Держите в уме стандартную архитектуру: DAO отдельно, сервисы — отдельно. Подробней пришлось бы написать поэму, в сети есть что-то про это, погуглите какие хорошие практики для написания дао и сервисов, и как их использовать хотя бы внутри MVC: http://programmers.stackexchange.com/questions/220909/service-layer-vs-dao-why-both
13) Блокирующие операции типа readline должны быть отдельно от пакетизированной логики. То есть вы сначала собираете все данные для операции, и только потом уже эту пачку данных отправляете на обработку в сервис. Читать строчку и тут же делать из нее класс — это фу.
14) Для всего что нужно закрывать — используйте try with resources.
Вообще насчет траев — провентилируйте как это сделано во фреймворках, все ли вы ошибочные ситуации рассмотрели. (Spring HibernateTemplate?)
Листы в хибере нельзя — при изменении состава коллекции происходит сначала удаление всего, а потом куча инсертов. equals и hashCode надо переопределить на основе айдишника.
да и вообще, если у нас id сгенерирован, то уже по смыслу equals не должен его учитывать.
Иначе окажется, что два элемента Set'а, совершенно одинаковые по контенту, но разные по id (о котором мы даже ничего не знаем), окажутся не equals — бред же. Equals должен сравнивать значимый контент
афтары как бы хотят нам сказать в документации, что эквивалентность мы должны задавать согласно «уникальному бизенс-ключу».
Но откуда взять этот ключ они не рассказали
получается, надо бы взять, и втащить под ключ большинство полей базы
но тогда критически просядет перфоманс
короче, это косяк Хиба, он не должен был использовать стандартные equals и hashcode, а теперь уже легаси и поздно что-то менять
Почему же бред? Если id разные — значит в БД это разные записи, значит похожие, но разные сущности. И id-то вообще-то и явлется по сути единственны обязательным и уникальным идентификатором объекта. Я не говою, кстати, что его должна генерировать БД. Если хочется — можно его генерить саому, можно туда класть UUID или timestamp, всё что угодно.
Или вы говорили про дефолтный id?
я както немного не готов к такому повороту событий)
6. ну без нормального окружения не будет хотя бы JTA, верно? Нужно будет специально с этим пердолиться, например: https://spring.io/blog/2011/08/15/configuring-spring-and-jta-without-full-java-ee/ Ну там аннотации отвалятся, еще что-то. Не то чтобы этого нельзя было решить за вечер, поллитры водки и полпалки колбасы. Но он ведь хотел как проще и удобней, а отказавшись от преднастроенной среды application server'а, он как бы напротив бегает и собирает лбом все грабли. Есть готовые практики, как это всё должно работать, если ты далеко от них уходишь, не понимая что происходит — то страдаешь
10. нормальный equals написать чудовищно сложно. Даже без всякого хибернейта, это просто теоретическая проблема ООП. Вот что сразу же гуглится по теме: http://www.artima.com/lejava/articles/equality.html
addEntity возвращающее void, внутри себя проглатывающее экзепшен — это Очень Плохо. На экзепшене надо или экзепшен прокидывать дальше (и обречь пользователя на его проверку) или просто возвращать false
16) хороший паттерн для операций с гарантированным исполнением и сокрытием ошибок: в самой первой строчке объявляется переменная result, в самой последней строчке она возвращается. Соответственно у функции только один вход, и только один выход. Никаких экзепшенов кроме критических ошибок и никаких return'ов между ними. Это позволяет читателям вашего кода не сойти с ума при попытке проанализировать ветви исполнения.
если вам нужно негарантированное исполнение (может результат есть, а может и нет) — используйте Optional. Или встроенный Optional из Java8, или тот что в Guava в случае устаревшей джавы. А все проверки на null, size==0 и подобное нужно по возможности выкашивать — никогда не знаешь, когда бахнет.
Коли уж речь зашла о Spring, то проще (и, как мне кажется, лучше) воспользоваться Spring Boot, а там уже просится Spring Data в которой уже есть практически все необходимые базовые CRUD-операции, а большинство более сложных кейсов можно сделать просто названием метода. Базовый туториал по последнему — http://projects.spring.io/spring-data/#quick-start
Про 16 пункт отдельно — это спорная практика. То есть есть ее адепты, их аргументация понятна. Аргументация оппонентов тоже прозрачная — читать такой код порой очень сложно, потому что вместо выхода где-то вначале функции «переменная» тащится через всю функцию. Поэтому я бы не рекомендовал такой паттерн с разбегу, во всяком случае это повод для дискуссии, а не 100% работающая рекомендация.
Есть идея «абзацев». Абзац в коде — это какая-то сгруппированный исключительно по смыслу набор строк. Такой что в принципе, его можно было бы выделить в функцию, но не нужно, т.к. он не предназначен для реального переиспользования (а объявление функции — это как раз инструкция — ты должен это переиспользовать, а не писать велосипеды).
Образно это как-то так:
public int something:
____читаем из базы, читаем из базы, читаем из базы
____читаем из базы, читаем из базы, читаем из базы
____читаем из базы, читаем из базы, читаем из базы
____фильтруем, фильтруем, фильтруем
____фильтруем, фильтруем, фильтруем
____фильтруем, фильтруем, фильтруем
____пишем назад в базу пишем назад в базу пишем назад в базу
____пишем назад в базу пишем назад в базу пишем назад в базу
____пишем назад в базу пишем назад в базу пишем назад в базу
Сама анатомия абзаца примерно такая:
1) //Комментарий, что делает абзац, если там сложная магия
2) Проверка предусловий и глобальных инвариантов
3) Тело абзаца — основная работа
4) Проверка постусловий и глобальных инвариантов
5) Фиксация результата: в переменную, или в глобальный result
** Редактор хабры как-то не очень расположен к написанию в нем кода, поэтому тут надо включить фантазию **
Так вот идея в том, что все fail-fast и быстрые результаты должны проходить строго по границам абзаца.
Еще хорошо делать, чтобы все ресурсы (типа долгоживущих переменных) были объявлены до абзаца, и освобождены только после него.
Если же начать пихать быстрые переходы прямо посреди абзаца, код теряет читабельность и предсказуемость.
Если начать пихать ресурсы прямо посреди абзаца и там же освобождать, то работа с этими ресурсами (например, последующий рефакторинг метода для поддержки многопоточности) становится затруднительным.
Метод целиком в каком-то смысле сам по себе является абзацем. Поэтому логично там в самом начале ставить глобальный result и возвращать его в конце, когда это реально удобно.
Человек пытается разобраться с Hibernate. А вы в комментариях ему рекомендуете Spring, Tomcat, транзакции — вроде как это всё другие темы. Почему бы не рассмотреть только одно? Понятно, сейчас скажете, что оно всё используется всегда вместе, но вот захотелось разобраться с чем-то одним и без всякой магии. Вон этот ваш HibernateTemplate, который даже EntityManager позволяет скрыть, он же вроде как в основе всего этого Hibernate.
2) Java в современном мире почти никогда не используется вне аппликейшен сервера (за исключением всякого эмбеддед, эклипс-платформы итп — но тогда ты скорей всгео не будешь юзать Хиб для MySQL!). Так что сделать минимальную war'ку и засунуть в аппликейшен сервер — это необходимое условие любого туториала по теме.
Чувак решил разобраться с хибом и разобрался так, что пришел к неверным выводам. Ну хорошо что он вообще разобрался, конечно, а вот теперь идет работа над ошибками.
2) Он УЖЕ использует транзакции. Но таким способом, когда надо в них разбираться и писать кучу кода. Аннотация @Transactional из Spring заменяет весь этот код, и в ней не нужно ничего понимать.
3) «но вот захотелось разобраться с чем-то одним и без всякой магии»
вот этот самая писечка.
В его случае он хотел не «без магии», а просто запинать хоть что-то.
А «без магии» в джаве не получится, тут всё — магия. Хибернейт весь целиком одна магия. От того что вы вручную напишите транзакции, магия рассеется чуть более чем никак. Как можно готовить магическое существо без магии?
Тогда уж ему нужно было написать свой ORM… но тогда не было бы времени собственно делать дело, писать код
9000) Если это статья человека, не разобравшегося в вопросе, то что она делает на Хабре в виде статьи? Кто-нибудь ее сейчас себе скопипастит в реальный код и начнется капец. Можно я тогда тоже начну сливать свои промежуточные брейндампы? Вот прямо сейчас пойду и солью пыщ пыщ на сто страниц какое говно логеры в жабе, это ок? :))
2) В современном мире микросервисов зачастую аппсервер не нужен, достаточно какого-нить рэтпака, основанного на нетти. А ещё часто встраивают аппсервер прямо в приложение: dropwizard, spring boot, wildfly swarm…
3) В джаве вообще нет магии. Другое дело что сначала лучше пройтись по верхам, а потом уже погружаться в то, как сделали так чтобы нам не надо было писать кучу бойлерплейта.
про swarm не знаю, но судя по тому, как его котируют стандартофилы, там тоже полный фарш
то есть мы наверное говорим об одном и том же, разница только как широко понимать слово «аппсервер»
Не обязательно томкат, можно и андертоу. Отличается для пользователя тем, что не надо собирать варник, да и не надо понимать на первом этапе что такое аппсервер и зачем надо. А если мы пишем ratpack приложение — то у нас и вовсе нет аппсервера никакого в приложении.
Ну да, конечно, не нужно. А потом человек начнет пихать эту аннотацию где только можно и прострелит себе ногу.
https://www.ibm.com/developerworks/library/j-ts1/
Считаю что один вход и один выход — плохая идея. fail-fast может и чиатется чуть хуже, зато работает чуть лучше.
Другие варианты синглтонов есть, например, здесь: https://habrahabr.ru/post/129494/
1. Так вот. Здесь написан лютый ад. Который приведет к куче проблем. Мы тут поревьюили этот туториал, и никак не оправимся от шока, кровь стынет в жилах. В 2016 году всё это делается немного по-другому…
PS — Отлично, все скорее всего так и есть, по сему спорить и не буду. Но, как писал выше, отталкивался от того, что нашел…
2. Возможно, стоит написать книжку по Hibernate на русском языке, где такие вопросы будут подробно рассмотрены?
PS А вот тут, смотри позицию ниже за номером 3.
3. По вопросу передачи знаний — обычно оно передается от учителя к ученику в джава-компаниях. Код, в котором сто сорок раз скопипастана кривая обертка запуска функции в транзакции, просто не пройдет первое же ревью. Там достаточно всего несколько дней, чтобы набить шишки…
PS То есть, отлавливать чужую практику в нормальном режиме без попадания в одну из адекватно — практикующих организация практически бесполезно (тут даже уже пошло взаимо-копание среди «профи» в стиле, в какой руке нужно держать солонку, когда солишь яичницу). Это тоже хорошо, в споре — истина. Но вопрос проще — а где еще набивать руку, если конторы хотят хоть с каким то опытом, а тьюторить им смысла нет, ибо учат только своих…
Я с большим бы удовольствием попал в организацию, где можно начать с начала и правильно и «набить шишки...» или набить «правильные» шишки, но спотыкаюсь о порог вхождения. Может кто подскажет мне с этим вопросом?
Не идти в конторы, где Hibernate является обязательным, идти туда, где он является дополнительным плюсом. Потому что там где он обязателен (когда-то у меня такое было) спрашивают всякие сложные штуки (я спрашивал) — уровни кеширования, SELECT NEW, разные API Для построения запросов, наследование…
Боюсь что это вопрос везения — когда-то я имел нерелевантный опыт тоже и устроился джуном. Но я вообще не программировал к тому моменту.
А вы, так как программировали, имеете ещё один путь — контрибутить в opensource java проекты на гитхабе и поместить ссылку на свой профиль гихабовский в резюме.
Пока делал сам на сам, клиент не видит, что внутри — работает и ладно. А когда решил устроиться куда посерьезнее, то получил по ушам на грани вылета с испытательного. Хотя у него и вполне настоящий сертификат Специалиста по 1С.
Было в районе 23 лет (может чуть меньше). Если начать фрилансить — то получится чисто индусское программирование, не стоит. А могу узнать в каком вы городе находитесь?
Это заканчивается вот так…
Большое спасибо за Ваш интерес, проявленный к нашей открытой вакансии «Младший разработчик». К сожалению, в настоящий момент мы не готовы сделать Вам это предложение. Мы внимательно ознакомились с Вашим резюме, и, возможно, вернемся к Вашей кандидатуре, когда у нас возникнет такая потребность.
Ну и да, по Hibernate есть отличная книга
что конкретно вам подсказать? Нельзя же лечить от непонятно какого заболевания. Чего вам не хватает — источников знаний, практики, волевого решения о направлении темы изучения, чего-то еще?
аккуратно представьте, что вы хотите получить, например, через 1 год, или через 3 года. Кем вы хотите стать, что уметь, и так далее. Не те «через 3 года» что спрашивают на собеседовании, а на самом деле. Потом сделайте diff между желаемым и действительным (что вы умеете сейчас) — и вот у вас есть стратегический план развития. Очень простой алгоритм.
желаемое можно описать здесь, может кто подскажет, что именно вам нужно изучать (если ваша проблема именно в нехватке источников информации)
А где выход?
Очень точно сказано. Да.
Более того, если вы сидите в пещере (или в гараже) и в одиночку медетируете на высокое просветление «умения программировать на джаве», то просветление это возможно даже придет — а рынку оно будет не нужно. Помните начало винрарного рассказа «так говорил заратустра»? :)
Вы ведь хотите на джаве писать не потому, что получите за это филдсовскую, а потому что хотите много денег и интересной комфортной работы? Плюшки дают за выполнение потребностей рынка -> нужно обучаться не просто чему-то абстрактно, а тому, что потребно на рынке -> нужно от этого рынка иметь постоянную обратную связь. Нельзя одновременно безвылазно медитировать в пещере и иметь обратную связь от внешнего мира :)
Есть опыт реабилитации людей «из пещеры» и «из гаража». Это очень долго и больно для всех участников. Просто не нужно туда залезать.
> но Вы смотрите на ситуацию с позиции «профи»
вот вы недавно преподавали алгоритмы, а я недавно (лет шесть назад) продавал бизнес-тренинги. Я не профи, а просто продвинутый делитант. И все рассуждения тут исключительно в рамках бытового здравого смысла. Вы как эксперт по алгоритмам намного более лучший потенциальный программист, чем был я.
> я не ставлю желание попасть вот именно туда, вот прям куда хочу и где всё будет так, как мне нравится…
а вот и зря не ставите :)
вы поймите в чем чисто бытовой смысл… Человек — это по сути сложная система для решения задач с обратной связью. Вы как преподаватель алгоритмов должны понимать, как это устроено:
— вначале идет фаза планирования (что ты хочешь сделать),
— потом фаза исполнения (реально что-то делаешь),
— потом фаза проверки (действительно ли мы добились чего хотели),
— потом фаза корректировки плана.
— и всё начинается заново по кругу
Plan, Do, Check, Act. https://en.wikipedia.org/wiki/PDCA
Если вы пропускаете какой-то из этих этапов, система с обратной связью не работает. Это не какой-то профессиональный снобизм, это просто свойство нашего мира :)
Если вы не ставите себе четкой цели, ваш план действий (или ваша карьера, или что-то еще), просто не рабоает.
Точнее, работает, но с ОЧЕНЬ низким КПД. Вы действительно настолько богаты, чтобы так разбрасываться своими силами? У вас столько свободного времени, столько лет жизни осталось?
> это правильно, но это история более далеких времен из будущего
То есть вас не устраивает размер временного диапазона, который надо запланировать? Не хватает мощности планировщика?
Ну окей, давайте запланируем не 3 года, а 3 месяца. Расскажите нам, чего вы добьетесь и чего изучите через три месяца.
Если вы не знаете чего хотеть, то тут есть два варианта:
1) Мы можем рассказать, что вам положено хотеть достичь через 3 месяца. Например, какие вещи касательно Java изучить.
2) Вы можете сами провести исследование и разобраться, чего нужно вам (или скорее — чего нужно рынку, если вы хотите рубить на этом бабло)
Насчет «Есть опыт реабилитации людей «из пещеры» и «из гаража». Это очень долго и больно для всех участников. Просто не нужно туда залезать».
Ну когда я туда «залез» — многих контор вообще не было еще на свете, и как бы я не рассчитывал что через 15 лет работы всех поставят к стенке в угоду оптимизации. Если вы умеете видеть на 15 лет вперед — я признаю вас не просто Гуру, это уровень Бога…
У вас столько свободного времени, столько лет жизни осталось?.. согласен и всеми конечностями «ЗА».
Но тут получается… я даже не знаю как это правильно описать алгоритмически — скорее всего рекурсия без условия выхода… Хочешь научиться водить — иди таксуй, но чтобы таксовать — нужны права, а чтобы получить права — научись водить… количество повторов — по вкусу…
А выхода здесь два — или не заходить, или все таки разорвать порочную практику «нерелевантного» опыта.
Если нет подкованых в джаве коллег, в качестве изначальной обратной связи можно использовать хабр или, например, фейсбук (кстати, если вы там есть, добавляйтесь: https://www.facebook.com/olegchir).
Меня очень вдохновляют видео с https://www.youtube.com/user/JUGRuVideo
Если живете в Москве/Питере, участвуйте в их мероприятиях
Если нет — хотя бы прорабатывайте видео.
Это весьма свежая и релевантная информация, поэтому ее можно считать обратной связью живой системы
(Но есть нюанс: там многие видики расчитаны на очень продвинутую аудиторию. Если вы уже прорвались через порог входа, то можете просто например, потихоньку прорабатывать, о чем там люди говорят)
Павел, вы там выше ушли в полную защиту из серии «Откуда мне знать как правильно, я же новичек». Это понятно, но абсолютно не конструктивно. Олег хоть и жестко, но описал более-менее все основные проблемы, которые стоит решить в этом примере.
Вместо того чтобы сокрушаться что опыт нельзя получить без работы, а работу без опыта — у вас есть отличная возможность скорректировать свои знания относительно рынка, поработать над кодом из топика и получить фидбек от людей, которые реально в этой индустрии работают. Почему вы этим не хотите воспользоваться?
Извините, перепутал. Эта скроее всего лучше: https://www.manning.com/books/java-persistence-with-hibernate
Некоторая практика применения Hibernate